<commit_before>#include "cansignalencoder_p.h"
#include <QCanBusFrame>
#include <log.h>

CanSignalEncoderPrivate::CanSignalEncoderPrivate(CanSignalEncoder* q, CanSignalEncoderCtx&& ctx)
    : _ctx(std::move(ctx))
    , q_ptr(q)
{
    initProps();

    connect(&_db, &CanDbHandler::sendCanDbRequest, q_ptr, &CanSignalEncoder::simBcastSnd);
    connect(&_db, &CanDbHandler::requestRedraw, q_ptr, &CanSignalEncoder::requestRedraw);
}

void CanSignalEncoderPrivate::initProps()
{
    for (const auto& p : _supportedProps) {
        _props[ComponentInterface::propertyName(p)];
    }
}

ComponentInterface::ComponentProperties CanSignalEncoderPrivate::getSupportedProperties() const
{
    return _supportedProps;
}

QJsonObject CanSignalEncoderPrivate::getSettings()
{
    QJsonObject json;

    for (const auto& p : _props) {
        json[p.first] = QJsonValue::fromVariant(p.second);
    }

    return json;
}

void CanSignalEncoderPrivate::setSettings(const QJsonObject& json)
{
    for (const auto& p : _supportedProps) {
        const QString& propName = ComponentInterface::propertyName(p);
        if (json.contains(propName))
            _props[propName] = json[propName].toVariant();
    }

    _db.updateCurrentDbFromProps();
}

void CanSignalEncoderPrivate::encodeSignal(const QString& name, const QVariant& val)
{
    auto nameSplit = name.split('_');

    if (nameSplit.size() < 2) {
        cds_error("Wrong signal name: {}", name.toStdString());
        return;
    }

    uint32_t id = nameSplit[0].toUInt(nullptr, 16);

    const CANmessages_t::value_type* msgDesc = nullptr;
    if (_db.getDb().count(id) > 0) {
        auto iter = _db.getDb().find(id);

        if (iter != _db.getDb().end()) {
            msgDesc = &(*iter);
        }
    }

    QString sigName = name.mid(name.indexOf("_") + 1);

    if (!msgDesc) {
        cds_warn("Msg '{:03x}' not found in DB", id);
        return;
    }

    for (auto& sig : msgDesc->second) {
        if (sig.signal_name == sigName.toStdString()) {
            if (_rawCache[id].size() < (int)msgDesc->first.dlc) {
                cds_info("Setting up new cache for {:03x} msg", id);
                // Set chache for the first time
                _rawCache[id].fill(0, msgDesc->first.dlc);
            }

            if (_rawCache[id].size() * 8 >= sig.startBit + sig.signalSize) {

                signalToRaw(id, sig, val, msgDesc->first.updateCycle);
                return;
            } else {
                cds_error("Payload size ('{}') for signal '{}' is too small. StartBit {}, signalSize {}",
                    _rawCache[id].size() * 8, sig.signal_name, sig.startBit, sig.signalSize);
            }
        }
    }

    cds_warn("Failed to find '{}' signal in '{:03x}' msg", sigName.toStdString(), id);

    return;
}

void CanSignalEncoderPrivate::signalToRaw(
    const uint32_t id, const CANsignal& sigDesc, const QVariant& sigVal, const uint32_t updateCycle)
{
    if (sigDesc.factor == 0) {
        cds_error("Factor for {} signal is 0! Singal encoding failed.", sigDesc.signal_name);
        return;
    }

    int64_t rawVal = static_cast<int64_t>(std::llround((sigVal.toDouble() - sigDesc.offset) / sigDesc.factor));
    uint8_t* data = (uint8_t*)_rawCache[id].data();

    if (sigDesc.byteOrder == 0) {
        // little endian
        auto bit = sigDesc.startBit;
        for (int bitpos = 0; bitpos < sigDesc.signalSize; bitpos++) {
            // clear bit first
            data[bit / 8] &= ~(1U << (bit % 8));
            // set bit
            data[bit / 8] |= ((rawVal >> bitpos) & 1U) << (bit % 8);
            bit++;
        }
    } else {
        // motorola / big endian mode
        auto bit = sigDesc.startBit;
        for (int bitpos = 0; bitpos < sigDesc.signalSize; bitpos++) {
            // clear bit first
            data[bit / 8] &= ~(1U << (bit % 8));
            // set bit
            data[bit / 8] |= ((rawVal >> (sigDesc.signalSize - bitpos - 1)) & 1U) << (bit % 8);

            bit++;
        }
    }

    if (updateCycle == 0) {
        // Send raw frame if cycle for message is not defined
        QCanBusFrame frame(id, _rawCache[id]);

        emit q_ptr->sndFrame(frame);
    }
}

void CanSignalEncoderPrivate::initCacheAndTimers()
{
    _cycleTimers.clear();
    _rawCache.clear();

    for (const auto& msg : _db.getDb()) {
        if (msg.first.initValue.length()) {
            _rawCache[msg.first.id] = QByteArray::fromHex(msg.first.initValue.c_str());
        }

        if (msg.first.updateCycle) {
            QTimer* timer = new QTimer;
            timer->setInterval(msg.first.updateCycle);
            connect(timer, &QTimer::timeout, [this, msg] {
                QCanBusFrame frame;
                frame.setFrameId(msg.first.id);
                if (_rawCache[msg.first.id].size() < (int)msg.first.dlc) {
                    cds_info("Setting up new cache for {:03x} msg", msg.first.id);
                    // Set chache for the first time
                    _rawCache[msg.first.id].fill(0, msg.first.dlc);
                }

                frame.setPayload(_rawCache[msg.first.id]);
                emit q_ptr->sndFrame(frame);
            });

            _cycleTimers.push_back(std::make_unique<QTimer>());
            _cycleTimers.back().reset(timer);
        }

        if (msg.first.updateCycle || msg.first.initValue.length()) {
            cds_debug("Settings for msg '{:03x}', cycle: {}, initValue: {}", msg.first.id, msg.first.updateCycle,
                msg.first.initValue);
        }
    }

}
<commit_msg>Fix typos in cansignalencoder_p.cpp (#230)<commit_after>#include "cansignalencoder_p.h"
#include <QCanBusFrame>
#include <log.h>

CanSignalEncoderPrivate::CanSignalEncoderPrivate(CanSignalEncoder* q, CanSignalEncoderCtx&& ctx)
    : _ctx(std::move(ctx))
    , q_ptr(q)
{
    initProps();

    connect(&_db, &CanDbHandler::sendCanDbRequest, q_ptr, &CanSignalEncoder::simBcastSnd);
    connect(&_db, &CanDbHandler::requestRedraw, q_ptr, &CanSignalEncoder::requestRedraw);
}

void CanSignalEncoderPrivate::initProps()
{
    for (const auto& p : _supportedProps) {
        _props[ComponentInterface::propertyName(p)];
    }
}

ComponentInterface::ComponentProperties CanSignalEncoderPrivate::getSupportedProperties() const
{
    return _supportedProps;
}

QJsonObject CanSignalEncoderPrivate::getSettings()
{
    QJsonObject json;

    for (const auto& p : _props) {
        json[p.first] = QJsonValue::fromVariant(p.second);
    }

    return json;
}

void CanSignalEncoderPrivate::setSettings(const QJsonObject& json)
{
    for (const auto& p : _supportedProps) {
        const QString& propName = ComponentInterface::propertyName(p);
        if (json.contains(propName))
            _props[propName] = json[propName].toVariant();
    }

    _db.updateCurrentDbFromProps();
}

void CanSignalEncoderPrivate::encodeSignal(const QString& name, const QVariant& val)
{
    auto nameSplit = name.split('_');

    if (nameSplit.size() < 2) {
        cds_error("Wrong signal name: {}", name.toStdString());
        return;
    }

    uint32_t id = nameSplit[0].toUInt(nullptr, 16);

    const CANmessages_t::value_type* msgDesc = nullptr;
    if (_db.getDb().count(id) > 0) {
        auto iter = _db.getDb().find(id);

        if (iter != _db.getDb().end()) {
            msgDesc = &(*iter);
        }
    }

    QString sigName = name.mid(name.indexOf("_") + 1);

    if (!msgDesc) {
        cds_warn("Msg '{:03x}' not found in DB", id);
        return;
    }

    for (auto& sig : msgDesc->second) {
        if (sig.signal_name == sigName.toStdString()) {
            if (_rawCache[id].size() < (int)msgDesc->first.dlc) {
                cds_info("Setting up new cache for {:03x} msg", id);
                // Set cache for the first time
                _rawCache[id].fill(0, msgDesc->first.dlc);
            }

            if (_rawCache[id].size() * 8 >= sig.startBit + sig.signalSize) {

                signalToRaw(id, sig, val, msgDesc->first.updateCycle);
                return;
            } else {
                cds_error("Payload size ('{}') for signal '{}' is too small. StartBit {}, signalSize {}",
                    _rawCache[id].size() * 8, sig.signal_name, sig.startBit, sig.signalSize);
            }
        }
    }

    cds_warn("Failed to find '{}' signal in '{:03x}' msg", sigName.toStdString(), id);

    return;
}

void CanSignalEncoderPrivate::signalToRaw(
    const uint32_t id, const CANsignal& sigDesc, const QVariant& sigVal, const uint32_t updateCycle)
{
    if (sigDesc.factor == 0) {
        cds_error("Factor for {} signal is 0! Signal encoding failed.", sigDesc.signal_name);
        return;
    }

    int64_t rawVal = static_cast<int64_t>(std::llround((sigVal.toDouble() - sigDesc.offset) / sigDesc.factor));
    uint8_t* data = (uint8_t*)_rawCache[id].data();

    if (sigDesc.byteOrder == 0) {
        // little endian
        auto bit = sigDesc.startBit;
        for (int bitpos = 0; bitpos < sigDesc.signalSize; bitpos++) {
            // clear bit first
            data[bit / 8] &= ~(1U << (bit % 8));
            // set bit
            data[bit / 8] |= ((rawVal >> bitpos) & 1U) << (bit % 8);
            bit++;
        }
    } else {
        // motorola / big endian mode
        auto bit = sigDesc.startBit;
        for (int bitpos = 0; bitpos < sigDesc.signalSize; bitpos++) {
            // clear bit first
            data[bit / 8] &= ~(1U << (bit % 8));
            // set bit
            data[bit / 8] |= ((rawVal >> (sigDesc.signalSize - bitpos - 1)) & 1U) << (bit % 8);

            bit++;
        }
    }

    if (updateCycle == 0) {
        // Send raw frame if cycle for message is not defined
        QCanBusFrame frame(id, _rawCache[id]);

        emit q_ptr->sndFrame(frame);
    }
}

void CanSignalEncoderPrivate::initCacheAndTimers()
{
    _cycleTimers.clear();
    _rawCache.clear();

    for (const auto& msg : _db.getDb()) {
        if (msg.first.initValue.length()) {
            _rawCache[msg.first.id] = QByteArray::fromHex(msg.first.initValue.c_str());
        }

        if (msg.first.updateCycle) {
            QTimer* timer = new QTimer;
            timer->setInterval(msg.first.updateCycle);
            connect(timer, &QTimer::timeout, [this, msg] {
                QCanBusFrame frame;
                frame.setFrameId(msg.first.id);
                if (_rawCache[msg.first.id].size() < (int)msg.first.dlc) {
                    cds_info("Setting up new cache for {:03x} msg", msg.first.id);
                    // Set cache for the first time
                    _rawCache[msg.first.id].fill(0, msg.first.dlc);
                }

                frame.setPayload(_rawCache[msg.first.id]);
                emit q_ptr->sndFrame(frame);
            });

            _cycleTimers.push_back(std::make_unique<QTimer>());
            _cycleTimers.back().reset(timer);
        }

        if (msg.first.updateCycle || msg.first.initValue.length()) {
            cds_debug("Settings for msg '{:03x}', cycle: {}, initValue: {}", msg.first.id, msg.first.updateCycle,
                msg.first.initValue);
        }
    }

}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/MemoryView.hpp>
#include <Nazara/Core/Stream.hpp>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	/*!
	* \ingroup core
	* \class Nz::ResourceLoader
	* \brief Core class that represents a loader of resources
	*/

	/*!
	* \brief Checks whether the extension of the file is supported
	* \return true if supported
	*
	* \param extension Extension of the file
	*/
	template<typename Type, typename Parameters>
	bool ResourceLoader<Type, Parameters>::IsExtensionSupported(const String& extension)
	{
		for (Loader& loader : Type::s_loaders)
		{
			ExtensionGetter isExtensionSupported = std::get<0>(loader);

			if (isExtensionSupported && isExtensionSupported(extension))
				return true;
		}

		return false;
	}

	/*!
	* \brief Loads a resource from a filepath and parameters
	* \return true if successfully loaded
	*
	* \param resource Resource to load
	* \param filePath Path to the resource
	* \param parameters Parameters for the load
	*
	* \remark Produces a NazaraError if resource is nullptr with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraError if parameters are invalid with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraError if filePath has no extension
	* \remark Produces a NazaraError if file count not be opened
	* \remark Produces a NazaraWarning if loader failed
	* \remark Produces a NazaraError if all loaders failed or no loader was found
	*/
	template<typename Type, typename Parameters>
	bool ResourceLoader<Type, Parameters>::LoadFromFile(Type* resource, const String& filePath, const Parameters& parameters)
	{
		#if NAZARA_CORE_SAFE
		if (!resource)
		{
			NazaraError("Pointer invalid");
			return false;
		}

		if (!parameters.IsValid())
		{
			NazaraError("Invalid parameters");
			return false;
		}
		#endif

		String path = File::NormalizePath(filePath);
		String ext = path.SubStringFrom('.', -1, true).ToLower();
		if (ext.IsEmpty())
		{
			NazaraError("Failed to get file extension from \"" + filePath + '"');
			return false;
		}

		File file(path); // Ouvert seulement en cas de besoin

		bool found = false;
		for (Loader& loader : Type::s_loaders)
		{
			ExtensionGetter isExtensionSupported = std::get<0>(loader);
			if (!isExtensionSupported || !isExtensionSupported(ext))
				continue;

			StreamChecker checkFunc = std::get<1>(loader);
			StreamLoader streamLoader = std::get<2>(loader);
			FileLoader fileLoader = std::get<3>(loader);

			if (checkFunc && !file.IsOpen())
			{
				if (!file.Open(OpenMode_ReadOnly))
				{
					NazaraError("Failed to load file: unable to open \"" + filePath + '"');
					return false;
				}
			}

			Ternary recognized = Ternary_Unknown;
			if (fileLoader)
			{
				if (checkFunc)
				{
					file.SetCursorPos(0);

					recognized = checkFunc(file, parameters);
					if (recognized == Ternary_False)
						continue;
					else
						found = true;
				}
				else
				{
					recognized = Ternary_Unknown;
					found = true;
				}

				if (fileLoader(resource, filePath, parameters))
				{
					resource->SetFilePath(filePath);
					return true;
				}
			}
			else
			{
				file.SetCursorPos(0);

				recognized = checkFunc(file, parameters);
				if (recognized == Ternary_False)
					continue;
				else if (recognized == Ternary_True)
					found = true;

				file.SetCursorPos(0);

				if (streamLoader(resource, file, parameters))
				{
					resource->SetFilePath(filePath);
					return true;
				}
			}

			if (recognized == Ternary_True)
				NazaraWarning("Loader failed");
		}

		if (found)
			NazaraError("Failed to load file: all loaders failed");
		else
			NazaraError("Failed to load file: no loader found for extension \"" + ext + '"');

		return false;
	}

	/*!
	* \brief Loads a resource from a raw memory, a size and parameters
	* \return true if successfully loaded
	*
	* \param resource Resource to load
	* \param data Raw memory of the resource
	* \param size Size available for the read
	* \param parameters Parameters for the load
	*
	* \remark Produces a NazaraError if resource is nullptr with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraError if size is 0 with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraError if parameters are invalid with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraWarning if loader failed
	* \remark Produces a NazaraError if all loaders failed or no loader was found
	*/
	template<typename Type, typename Parameters>
	bool ResourceLoader<Type, Parameters>::LoadFromMemory(Type* resource, const void* data, unsigned int size, const Parameters& parameters)
	{
		#if NAZARA_CORE_SAFE
		if (!resource)
		{
			NazaraError("Pointer invalid");
			return false;
		}

		if (size == 0)
		{
			NazaraError("No data to load");
			return false;
		}

		if (!parameters.IsValid())
		{
			NazaraError("Invalid parameters");
			return false;
		}
		#endif

		MemoryView stream(data, size);

		bool found = false;
		for (Loader& loader : Type::s_loaders)
		{
			StreamChecker checkFunc = std::get<1>(loader);
			StreamLoader streamLoader = std::get<2>(loader);
			MemoryLoader memoryLoader = std::get<4>(loader);

			Ternary recognized = Ternary_Unknown;
			if (memoryLoader)
			{
				if (checkFunc)
				{
					stream.SetCursorPos(0);

					recognized = checkFunc(stream, parameters);
					if (recognized == Ternary_False)
						continue;
					else
						found = true;
				}
				else
				{
					recognized = Ternary_Unknown;
					found = true;
				}

				if (memoryLoader(resource, data, size, parameters))
					return true;
			}
			else
			{
				stream.SetCursorPos(0);

				recognized = checkFunc(stream, parameters);
				if (recognized == Ternary_False)
					continue;
				else if (recognized == Ternary_True)
					found = true;

				stream.SetCursorPos(0);

				if (streamLoader(resource, stream, parameters))
					return true;
			}

			if (recognized == Ternary_True)
				NazaraWarning("Loader failed");
		}

		if (found)
			NazaraError("Failed to load file: all loaders failed");
		else
			NazaraError("Failed to load file: no loader found");

		return false;
	}

	/*!
	* \brief Loads a resource from a stream and parameters
	* \return true if successfully loaded
	*
	* \param resource Resource to load
	* \param stream Stream of the resource
	* \param parameters Parameters for the load
	*
	* \remark Produces a NazaraError if resource is nullptr with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraError if stream has no data with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraError if parameters are invalid with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraWarning if loader failed
	* \remark Produces a NazaraError if all loaders failed or no loader was found
	*/
	template<typename Type, typename Parameters>
	bool ResourceLoader<Type, Parameters>::LoadFromStream(Type* resource, Stream& stream, const Parameters& parameters)
	{
		#if NAZARA_CORE_SAFE
		if (!resource)
		{
			NazaraError("Pointer invalid");
			return false;
		}

		if (stream.GetSize() == 0 || stream.GetCursorPos() >= stream.GetSize())
		{
			NazaraError("No data to load");
			return false;
		}

		if (!parameters.IsValid())
		{
			NazaraError("Invalid parameters");
			return false;
		}
		#endif

		UInt64 streamPos = stream.GetCursorPos();
		bool found = false;
		for (Loader& loader : Type::s_loaders)
		{
			StreamChecker checkFunc = std::get<1>(loader);
			StreamLoader streamLoader = std::get<2>(loader);

			stream.SetCursorPos(streamPos);

			// Does the loader support these data ?
			Ternary recognized = checkFunc(stream, parameters);
			if (recognized == Ternary_False)
				continue;
			else if (recognized == Ternary_True)
				found = true;

			// We move the stream to its old position
			stream.SetCursorPos(streamPos);

			// Load of the resource
			if (streamLoader(resource, stream, parameters))
				return true;

			if (recognized == Ternary_True)
				NazaraWarning("Loader failed");
		}

		if (found)
			NazaraError("Failed to load file: all loaders failed");
		else
			NazaraError("Failed to load file: no loader found");

		return false;
	}

	/*!
	* \brief Registers the loader
	*
	* \param extensionGetter A function to test whether the extension (as a string) is supported by this loader
	* \param checkFunc A function to check the stream with the parser
	* \param streamLoader A function to load the data from a stream in the resource
	* \param fileLoader Optional function to load the data from a file in the resource
	* \param memoryLoader Optional function to load the data from a raw memory in the resource
	*/
	template<typename Type, typename Parameters>
	void ResourceLoader<Type, Parameters>::RegisterLoader(ExtensionGetter extensionGetter, StreamChecker checkFunc, StreamLoader streamLoader, FileLoader fileLoader, MemoryLoader memoryLoader)
	{
		#if NAZARA_CORE_SAFE
		if (streamLoader)
		{
			if (!checkFunc)
			{
				NazaraError("StreamLoader present without StreamChecker");
				return;
			}
		}
		else if (!fileLoader && !memoryLoader)
		{
			NazaraError("Neither FileLoader nor MemoryLoader nor StreamLoader were present");
			return;
		}
		#endif

		Type::s_loaders.push_front(std::make_tuple(extensionGetter, checkFunc, streamLoader, fileLoader, memoryLoader));
	}

	/*!
	* \brief Unregisters the loader
	*
	* \param extensionGetter A function to test whether the extension (as a string) is supported by this loader
	* \param checkFunc A function to check the stream with the parser
	* \param streamLoader A function to load the data from a stream in the resource
	* \param fileLoader Optional function to load the data from a file in the resource
	* \param memoryLoader Optional function to load the data from a raw memory in the resource
	*/
	template<typename Type, typename Parameters>
	void ResourceLoader<Type, Parameters>::UnregisterLoader(ExtensionGetter extensionGetter, StreamChecker checkFunc, StreamLoader streamLoader, FileLoader fileLoader, MemoryLoader memoryLoader)
	{
		Type::s_loaders.remove(std::make_tuple(extensionGetter, checkFunc, streamLoader, fileLoader, memoryLoader));
	}
}

#include <Nazara/Core/DebugOff.hpp>
<commit_msg>Core/ResourceLoader: Replace checks by asserts<commit_after>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/MemoryView.hpp>
#include <Nazara/Core/Stream.hpp>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	/*!
	* \ingroup core
	* \class Nz::ResourceLoader
	* \brief Core class that represents a loader of resources
	*/

	/*!
	* \brief Checks whether the extension of the file is supported
	* \return true if supported
	*
	* \param extension Extension of the file
	*/
	template<typename Type, typename Parameters>
	bool ResourceLoader<Type, Parameters>::IsExtensionSupported(const String& extension)
	{
		for (Loader& loader : Type::s_loaders)
		{
			ExtensionGetter isExtensionSupported = std::get<0>(loader);

			if (isExtensionSupported && isExtensionSupported(extension))
				return true;
		}

		return false;
	}

	/*!
	* \brief Loads a resource from a file
	* \return true if successfully loaded
	*
	* \param resource Resource to load
	* \param filePath Path to the resource
	* \param parameters Parameters for the load
	*
	* \remark Produces a NazaraError if resource is nullptr with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraError if parameters are invalid with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraError if filePath has no extension
	* \remark Produces a NazaraError if file count not be opened
	* \remark Produces a NazaraWarning if loader failed
	* \remark Produces a NazaraError if all loaders failed or no loader was found
	*/
	template<typename Type, typename Parameters>
	bool ResourceLoader<Type, Parameters>::LoadFromFile(Type* resource, const String& filePath, const Parameters& parameters)
	{
		NazaraAssert(resource, "Invalid resource");
		NazaraAssert(parameters.IsValid(), "Invalid parameters");

		String path = File::NormalizePath(filePath);
		String ext = path.SubStringFrom('.', -1, true).ToLower();
		if (ext.IsEmpty())
		{
			NazaraError("Failed to get file extension from \"" + filePath + '"');
			return false;
		}

		File file(path); // Ouvert seulement en cas de besoin

		bool found = false;
		for (Loader& loader : Type::s_loaders)
		{
			ExtensionGetter isExtensionSupported = std::get<0>(loader);
			if (!isExtensionSupported || !isExtensionSupported(ext))
				continue;

			StreamChecker checkFunc = std::get<1>(loader);
			StreamLoader streamLoader = std::get<2>(loader);
			FileLoader fileLoader = std::get<3>(loader);

			if (checkFunc && !file.IsOpen())
			{
				if (!file.Open(OpenMode_ReadOnly))
				{
					NazaraError("Failed to load file: unable to open \"" + filePath + '"');
					return false;
				}
			}

			Ternary recognized = Ternary_Unknown;
			if (fileLoader)
			{
				if (checkFunc)
				{
					file.SetCursorPos(0);

					recognized = checkFunc(file, parameters);
					if (recognized == Ternary_False)
						continue;
					else
						found = true;
				}
				else
				{
					recognized = Ternary_Unknown;
					found = true;
				}

				if (fileLoader(resource, filePath, parameters))
				{
					resource->SetFilePath(filePath);
					return true;
				}
			}
			else
			{
				file.SetCursorPos(0);

				recognized = checkFunc(file, parameters);
				if (recognized == Ternary_False)
					continue;
				else if (recognized == Ternary_True)
					found = true;

				file.SetCursorPos(0);

				if (streamLoader(resource, file, parameters))
				{
					resource->SetFilePath(filePath);
					return true;
				}
			}

			if (recognized == Ternary_True)
				NazaraWarning("Loader failed");
		}

		if (found)
			NazaraError("Failed to load file: all loaders failed");
		else
			NazaraError("Failed to load file: no loader found for extension \"" + ext + '"');

		return false;
	}

	/*!
	* \brief Loads a resource from a raw memory, a size and parameters
	* \return true if successfully loaded
	*
	* \param resource Resource to load
	* \param data Raw memory of the resource
	* \param size Size available for the read
	* \param parameters Parameters for the load
	*
	* \remark Produces a NazaraError if resource is nullptr with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraError if size is 0 with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraError if parameters are invalid with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraWarning if loader failed
	* \remark Produces a NazaraError if all loaders failed or no loader was found
	*/
	template<typename Type, typename Parameters>
	bool ResourceLoader<Type, Parameters>::LoadFromMemory(Type* resource, const void* data, unsigned int size, const Parameters& parameters)
	{
		NazaraAssert(resource, "Invalid resource");
		NazaraAssert(data, "Invalid data pointer");
		NazaraAssert(size, "No data to load");
		NazaraAssert(parameters.IsValid(), "Invalid parameters");

		MemoryView stream(data, size);

		bool found = false;
		for (Loader& loader : Type::s_loaders)
		{
			StreamChecker checkFunc = std::get<1>(loader);
			StreamLoader streamLoader = std::get<2>(loader);
			MemoryLoader memoryLoader = std::get<4>(loader);

			Ternary recognized = Ternary_Unknown;
			if (memoryLoader)
			{
				if (checkFunc)
				{
					stream.SetCursorPos(0);

					recognized = checkFunc(stream, parameters);
					if (recognized == Ternary_False)
						continue;
					else
						found = true;
				}
				else
				{
					recognized = Ternary_Unknown;
					found = true;
				}

				if (memoryLoader(resource, data, size, parameters))
					return true;
			}
			else
			{
				stream.SetCursorPos(0);

				recognized = checkFunc(stream, parameters);
				if (recognized == Ternary_False)
					continue;
				else if (recognized == Ternary_True)
					found = true;

				stream.SetCursorPos(0);

				if (streamLoader(resource, stream, parameters))
					return true;
			}

			if (recognized == Ternary_True)
				NazaraWarning("Loader failed");
		}

		if (found)
			NazaraError("Failed to load file: all loaders failed");
		else
			NazaraError("Failed to load file: no loader found");

		return false;
	}

	/*!
	* \brief Loads a resource from a stream and parameters
	* \return true if successfully loaded
	*
	* \param resource Resource to load
	* \param stream Stream of the resource
	* \param parameters Parameters for the load
	*
	* \remark Produces a NazaraError if resource is nullptr with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraError if stream has no data with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraError if parameters are invalid with NAZARA_CORE_SAFE defined
	* \remark Produces a NazaraWarning if loader failed
	* \remark Produces a NazaraError if all loaders failed or no loader was found
	*/
	template<typename Type, typename Parameters>
	bool ResourceLoader<Type, Parameters>::LoadFromStream(Type* resource, Stream& stream, const Parameters& parameters)
	{
		NazaraAssert(resource, "Invalid resource");
		NazaraAssert(stream.GetCursorPos() >= stream.GetSize(), "No data to load");
		NazaraAssert(parameters.IsValid(), "Invalid parameters");

		UInt64 streamPos = stream.GetCursorPos();
		bool found = false;
		for (Loader& loader : Type::s_loaders)
		{
			StreamChecker checkFunc = std::get<1>(loader);
			StreamLoader streamLoader = std::get<2>(loader);

			stream.SetCursorPos(streamPos);

			// Does the loader support these data ?
			Ternary recognized = checkFunc(stream, parameters);
			if (recognized == Ternary_False)
				continue;
			else if (recognized == Ternary_True)
				found = true;

			// We move the stream to its old position
			stream.SetCursorPos(streamPos);

			// Load of the resource
			if (streamLoader(resource, stream, parameters))
				return true;

			if (recognized == Ternary_True)
				NazaraWarning("Loader failed");
		}

		if (found)
			NazaraError("Failed to load file: all loaders failed");
		else
			NazaraError("Failed to load file: no loader found");

		return false;
	}

	/*!
	* \brief Registers the loader
	*
	* \param extensionGetter A function to test whether the extension (as a string) is supported by this loader
	* \param checkFunc A function to check the stream with the parser
	* \param streamLoader A function to load the data from a stream in the resource
	* \param fileLoader Optional function to load the data from a file in the resource
	* \param memoryLoader Optional function to load the data from a raw memory in the resource
	*/
	template<typename Type, typename Parameters>
	void ResourceLoader<Type, Parameters>::RegisterLoader(ExtensionGetter extensionGetter, StreamChecker checkFunc, StreamLoader streamLoader, FileLoader fileLoader, MemoryLoader memoryLoader)
	{
		NazaraAssert(checkFunc || !streamLoader, "StreamLoader present without StreamChecker");
		NazaraAssert(fileLoader || memoryLoader || streamLoader, "A loader function is mandatory");

		Type::s_loaders.push_front(std::make_tuple(extensionGetter, checkFunc, streamLoader, fileLoader, memoryLoader));
	}

	/*!
	* \brief Unregisters the loader
	*
	* \param extensionGetter A function to test whether the extension (as a string) is supported by this loader
	* \param checkFunc A function to check the stream with the parser
	* \param streamLoader A function to load the data from a stream in the resource
	* \param fileLoader Optional function to load the data from a file in the resource
	* \param memoryLoader Optional function to load the data from a raw memory in the resource
	*/
	template<typename Type, typename Parameters>
	void ResourceLoader<Type, Parameters>::UnregisterLoader(ExtensionGetter extensionGetter, StreamChecker checkFunc, StreamLoader streamLoader, FileLoader fileLoader, MemoryLoader memoryLoader)
	{
		Type::s_loaders.remove(std::make_tuple(extensionGetter, checkFunc, streamLoader, fileLoader, memoryLoader));
	}
}

#include <Nazara/Core/DebugOff.hpp>
<|endoftext|>


<commit_before>#ifndef ARC_UTILITIES_MATH_HELPERS_HPP
#define ARC_UTILITIES_MATH_HELPERS_HPP

#include <vector>
#include <cmath>
#include <cstddef>
#include <iostream>
#include <cassert>

namespace EigenHelpers //TODO: Change namespace to ArcMath, breaking change
{
    ////////////////////////////////////////////////////////////////////////////
    // Misc
    ////////////////////////////////////////////////////////////////////////////

    inline bool CloseEnough(const double p1, const double p2, const double threshold)
    {
        const double real_threshold = std::abs(threshold);
        const double abs_delta = std::abs(p2 - p1);
        return abs_delta <= real_threshold;
    }

    inline bool CloseEnough(const std::vector<double> &v1, const std::vector<double> &v2,
                            const double threshold)
    {
        if(v1.size() != v2.size())
        {
            return false;
        }
        for(size_t i=0; i<v1.size(); i++)
        {
            if(!CloseEnough(v1[i], v2[i], threshold))
            {
                return false;
            }
        }
        return true;
    }

    // Inspired by Eigen's "isApprox" function
    inline bool IsApprox(const double p1, const double p2, const double precision)
    {
        const double smallest_element = std::min(std::abs(p1), std::abs(p2));
        const double threshold = precision * smallest_element;
        return CloseEnough(p1, p2, threshold);
    }

    // https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c
    // Returns -1, 0, or 1 depending on the sign of val
    template <typename T>
    inline int Sign(const T val)
    {
        return (T(0) < val) - (val < T(0));
    }

    ////////////////////////////////////////////////////////////////////////////
    // Interpolation functions
    ////////////////////////////////////////////////////////////////////////////

    inline double EnforceContinuousRevoluteBounds(const double value)
    {
        if ((value <= -M_PI) || (value > M_PI))
        {
            const double remainder = fmod(value, 2.0 * M_PI);
            if (remainder <= -M_PI)
            {
                return (remainder + (2.0 * M_PI));
            }
            else if (remainder > M_PI)
            {
                return (remainder - (2.0 * M_PI));
            }
            else
            {
                return remainder;
            }
        }
        else
        {
            return value;
        }
    }

    // TODO: this is almost the same as arc_helpers.hpp:ClampValueAndWarn(...)
    //       we should resolve this redundency, pick one place for this function
    template <typename FloatType>
    inline FloatType SafetyCheckUnitInterval(const FloatType ratio)
    {
        static_assert(std::is_floating_point<FloatType>::value, "Type must be a float type");
        FloatType real_ratio = ratio;
        if (real_ratio < 0.0)
        {
            real_ratio = 0.0;
            std::cerr << "Interpolation ratio < 0.0, set to 0.0 " << std::endl;
        }
        else if (real_ratio > 1.0)
        {
            real_ratio = 1.0;
            std::cerr << "Interpolation ratio > 1.0, set to 1.0" << std::endl;
        }
        return real_ratio;
    }

    inline double Interpolate(const double p1, const double p2, const double ratio)
    {
        // Safety check ratio
        const double real_ratio = SafetyCheckUnitInterval(ratio);
        // Interpolate
        // This is the numerically stable version, rather than  (p1 + (p2 - p1) * real_ratio)
        return ((p1 * (1.0 - real_ratio)) + (p2 * real_ratio));
    }

    inline double InterpolateContinuousRevolute(const double p1, const double p2, const double ratio)
    {
        // Safety check ratio
        const double real_ratio = SafetyCheckUnitInterval(ratio);
        // Safety check args
        const double real_p1 = EnforceContinuousRevoluteBounds(p1);
        const double real_p2 = EnforceContinuousRevoluteBounds(p2);
        // Interpolate
        double interpolated = 0.0;
        double diff = real_p2 - real_p1;
        if (std::abs(diff) <= M_PI)
        {
            interpolated = real_p1 + diff * real_ratio;
        }
        else
        {
            if (diff > 0.0)
            {
                diff = 2.0 * M_PI - diff;
            }
            else
            {
                diff = -2.0 * M_PI - diff;
            }
            interpolated = real_p1 - diff * real_ratio;
            // Input states are within bounds, so the following check is sufficient
            if (interpolated > M_PI)
            {
                interpolated -= 2.0 * M_PI;
            }
            else
            {
                if (interpolated < -M_PI)
                {
                    interpolated += 2.0 * M_PI;
                }
            }
        }
        return interpolated;
    }

    template <typename T1, typename T2>
    inline std::pair<T1, T2> Interpolate(const std::pair<T1, T2>& p1, const std::pair<T1, T2>& p2, const double ratio)
    {
        // Safety check ratio
        const double real_ratio = SafetyCheckUnitInterval(ratio);
        // Interpolate
        // This is the numerically stable version, rather than  (p1 + (p2 - p1) * real_ratio)
        return std::make_pair<T1, T2>(
                    (p1.first * (1.0 - real_ratio)) + (p2.first * real_ratio),
                    (p1.second * (1.0 - real_ratio)) + (p2.second * real_ratio));
    }

    template <typename T>
    inline std::vector<T> Interpolate(const std::vector<T>& v1, const std::vector<T>& v2, const double ratio)
    {
        // Safety check ratio
        const double real_ratio = SafetyCheckUnitInterval(ratio);
        // Safety check inputs
        const size_t len = v1.size();
        if (len != v2.size())
        {
            std::cerr << "Vectors to interpolate are different sizes (" << v1.size() << " versus " << v2.size() << ")" << std::endl;
            return std::vector<T>();
        }
        // Interpolate
        // This is the numerically stable version, rather than  (p1 + (p2 - p1) * real_ratio)
        std::vector<T> interped(len, 0);
        for (size_t idx = 0; idx < len; idx++)
        {
            interped[idx] = ((v1[idx] * (1.0 - real_ratio)) + (v2[idx] * real_ratio));
        }
        return interped;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Distance functions
    ////////////////////////////////////////////////////////////////////////////

    inline double SquaredDistance(const std::vector<double>& p1, const std::vector<double>& p2)
    {
        if (p1.size() == p2.size())
        {
            double distance = 0.0;
            for (size_t idx = 0; idx < p1.size(); idx++)
            {
                distance += (p2[idx] - p1[idx]) * (p2[idx] - p1[idx]);
            }
            return distance;
        }
        else
        {
            return INFINITY;
        }
    }

    inline double Distance(const std::vector<double>& p1, const std::vector<double>& p2)
    {
        if (p1.size() == p2.size())
        {
            return sqrt(SquaredDistance(p1, p2));
        }
        else
        {
            return INFINITY;
        }
    }

    inline double ContinuousRevoluteSignedDistance(const double p1, const double p2)
    {
        // Safety check args
        const double real_p1 = EnforceContinuousRevoluteBounds(p1);
        const double real_p2 = EnforceContinuousRevoluteBounds(p2);
        const double raw_distance = real_p2 - real_p1;
        if ((raw_distance <= -M_PI) || (raw_distance > M_PI))
        {
            if (raw_distance <= -M_PI)
            {
                return (-(2.0 * M_PI) - raw_distance);
            }
            else if (raw_distance > M_PI)
            {
                return ((2.0 * M_PI) - raw_distance);
            }
            else
            {
                return raw_distance;
            }
        }
        else
        {
            return raw_distance;
        }
    }

    inline double ContinuousRevoluteDistance(const double p1, const double p2)
    {
        return std::abs(ContinuousRevoluteSignedDistance(p1, p2));
    }

    inline double AddContinuousRevoluteValues(const double start, const double change)
    {
        return EnforceContinuousRevoluteBounds(start + change);
    }

    inline double GetContinuousRevoluteRange(const double start, const double end)
    {
        const double raw_range = ContinuousRevoluteSignedDistance(start, end);
        if (raw_range >= 0.0)
        {
            return raw_range;
        }
        else
        {
            return (2.0 * M_PI) + raw_range;
        }
    }

    inline bool CheckInContinuousRevoluteRange(const double start, const double range, const double val)
    {
        const double real_val = EnforceContinuousRevoluteBounds(val);
        const double real_start = EnforceContinuousRevoluteBounds(start);
        const double delta = ContinuousRevoluteSignedDistance(real_start, real_val);
        if (delta >= 0.0)
        {
            if (delta <= range)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            const double real_delta = (2.0 * M_PI) + delta;
            if (real_delta <= range)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    inline bool CheckInContinuousRevoluteBounds(const double start, const double end, const double val)
    {
        const double range = GetContinuousRevoluteRange(start, end);
        return CheckInContinuousRevoluteRange(start, range, val);
    }

    // DistanceFn must match the following interface: std::function<double(const T&, const T&)>
    template<typename T, class DistanceFn, typename Alloc = std::allocator<T>>
    inline double CalculateTotalDistance(const std::vector<T, Alloc>& path, const DistanceFn& distance_fn)
    {
        double total_dist = 0;
        for (size_t path_idx = 0; path_idx + 1 < path.size(); path_idx++)
        {
            const double delta = distance_fn(path[path_idx], path[path_idx + 1]);
            total_dist += delta;
        }
        return total_dist;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Averaging functions
    // Numerically more stable averages taken from http://people.ds.cam.ac.uk/fanf2/hermes/doc/antiforgery/stats.pdf
    ////////////////////////////////////////////////////////////////////////////

    inline double AverageStdVectorDouble(
            const std::vector<double>& values,
            const std::vector<double>& weights = std::vector<double>())
    {
        // Get the weights
        assert(values.size() > 0);
        assert((weights.size() == values.size()) || (weights.size() == 0));
        const bool use_weights = (weights.size() != 0);
        // Find the first element with non-zero weight
        size_t starting_idx = 0;
        while (starting_idx < weights.size() && weights[starting_idx] == 0.0)
        {
            starting_idx++;
        }
        // If all weights are zero, result is undefined
        assert(starting_idx < values.size());
        // Start the recursive definition with the base case
        double average = values[starting_idx];
        const double starting_weight = use_weights ? std::abs(weights[starting_idx]) : 1.0;
        assert(starting_weight > 0.0);
        double weights_running_sum = starting_weight;
        // Do the weighted averaging on the rest of the vectors
        for (size_t idx = starting_idx + 1; idx < values.size(); idx++)
        {
            const double weight = use_weights ? std::abs(weights[idx]) : 1.0;
            weights_running_sum += weight;
            const double effective_weight = weight / weights_running_sum;
            const double prev_average = average;
            const double current = values[idx];
            average = prev_average + (effective_weight * (current - prev_average));
        }
        return average;
    }

    inline double ComputeStdDevStdVectorDouble(const std::vector<double>& values, const double mean)
    {
        assert(values.size() > 0);
        if (values.size() == 1)
        {
            return 0.0;
        }
        else
        {
            const double inv_n_minus_1 = 1.0 / (double)(values.size() - 1);
            double stddev_sum = 0.0;
            for (size_t idx = 0; idx < values.size(); idx++)
            {
                const double delta = values[idx] - mean;
                stddev_sum += (delta * delta);
            }
            return std::sqrt(stddev_sum * inv_n_minus_1);
        }
    }

    inline double ComputeStdDevStdVectorDouble(const std::vector<double>& values)
    {
        const double mean = AverageStdVectorDouble(values);
        return ComputeStdDevStdVectorDouble(values, mean);
    }

    /*
     * This function does not actually deal with the continuous revolute space correctly,
     * it just assumes a normal real Euclidean space
     */
    inline double AverageContinuousRevolute(
            const std::vector<double>& angles,
            const std::vector<double>& weights = std::vector<double>())
    {
        return AverageStdVectorDouble(angles, weights);
    }
}

#endif //ARC_UTILITIES_MATH_HELPERS_HPP
<commit_msg>Minor style correction.<commit_after>#ifndef ARC_UTILITIES_MATH_HELPERS_HPP
#define ARC_UTILITIES_MATH_HELPERS_HPP

#include <vector>
#include <cmath>
#include <cstddef>
#include <iostream>
#include <cassert>

namespace EigenHelpers //TODO: Change namespace to ArcMath, breaking change
{
    ////////////////////////////////////////////////////////////////////////////
    // Misc
    ////////////////////////////////////////////////////////////////////////////

    inline bool CloseEnough(const double p1, const double p2, const double threshold)
    {
        const double real_threshold = std::abs(threshold);
        const double abs_delta = std::abs(p2 - p1);
        return abs_delta <= real_threshold;
    }

    inline bool CloseEnough(const std::vector<double>& v1, const std::vector<double>& v2,
                            const double threshold)
    {
        if(v1.size() != v2.size())
        {
            return false;
        }
        for(size_t i=0; i<v1.size(); i++)
        {
            if(!CloseEnough(v1[i], v2[i], threshold))
            {
                return false;
            }
        }
        return true;
    }

    // Inspired by Eigen's "isApprox" function
    inline bool IsApprox(const double p1, const double p2, const double precision)
    {
        const double smallest_element = std::min(std::abs(p1), std::abs(p2));
        const double threshold = precision * smallest_element;
        return CloseEnough(p1, p2, threshold);
    }

    // https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c
    // Returns -1, 0, or 1 depending on the sign of val
    template <typename T>
    inline int Sign(const T val)
    {
        return (T(0) < val) - (val < T(0));
    }

    ////////////////////////////////////////////////////////////////////////////
    // Interpolation functions
    ////////////////////////////////////////////////////////////////////////////

    inline double EnforceContinuousRevoluteBounds(const double value)
    {
        if ((value <= -M_PI) || (value > M_PI))
        {
            const double remainder = fmod(value, 2.0 * M_PI);
            if (remainder <= -M_PI)
            {
                return (remainder + (2.0 * M_PI));
            }
            else if (remainder > M_PI)
            {
                return (remainder - (2.0 * M_PI));
            }
            else
            {
                return remainder;
            }
        }
        else
        {
            return value;
        }
    }

    // TODO: this is almost the same as arc_helpers.hpp:ClampValueAndWarn(...)
    //       we should resolve this redundency, pick one place for this function
    template <typename FloatType>
    inline FloatType SafetyCheckUnitInterval(const FloatType ratio)
    {
        static_assert(std::is_floating_point<FloatType>::value, "Type must be a float type");
        FloatType real_ratio = ratio;
        if (real_ratio < 0.0)
        {
            real_ratio = 0.0;
            std::cerr << "Interpolation ratio < 0.0, set to 0.0 " << std::endl;
        }
        else if (real_ratio > 1.0)
        {
            real_ratio = 1.0;
            std::cerr << "Interpolation ratio > 1.0, set to 1.0" << std::endl;
        }
        return real_ratio;
    }

    inline double Interpolate(const double p1, const double p2, const double ratio)
    {
        // Safety check ratio
        const double real_ratio = SafetyCheckUnitInterval(ratio);
        // Interpolate
        // This is the numerically stable version, rather than  (p1 + (p2 - p1) * real_ratio)
        return ((p1 * (1.0 - real_ratio)) + (p2 * real_ratio));
    }

    inline double InterpolateContinuousRevolute(const double p1, const double p2, const double ratio)
    {
        // Safety check ratio
        const double real_ratio = SafetyCheckUnitInterval(ratio);
        // Safety check args
        const double real_p1 = EnforceContinuousRevoluteBounds(p1);
        const double real_p2 = EnforceContinuousRevoluteBounds(p2);
        // Interpolate
        double interpolated = 0.0;
        double diff = real_p2 - real_p1;
        if (std::abs(diff) <= M_PI)
        {
            interpolated = real_p1 + diff * real_ratio;
        }
        else
        {
            if (diff > 0.0)
            {
                diff = 2.0 * M_PI - diff;
            }
            else
            {
                diff = -2.0 * M_PI - diff;
            }
            interpolated = real_p1 - diff * real_ratio;
            // Input states are within bounds, so the following check is sufficient
            if (interpolated > M_PI)
            {
                interpolated -= 2.0 * M_PI;
            }
            else
            {
                if (interpolated < -M_PI)
                {
                    interpolated += 2.0 * M_PI;
                }
            }
        }
        return interpolated;
    }

    template <typename T1, typename T2>
    inline std::pair<T1, T2> Interpolate(const std::pair<T1, T2>& p1, const std::pair<T1, T2>& p2, const double ratio)
    {
        // Safety check ratio
        const double real_ratio = SafetyCheckUnitInterval(ratio);
        // Interpolate
        // This is the numerically stable version, rather than  (p1 + (p2 - p1) * real_ratio)
        return std::make_pair<T1, T2>(
                    (p1.first * (1.0 - real_ratio)) + (p2.first * real_ratio),
                    (p1.second * (1.0 - real_ratio)) + (p2.second * real_ratio));
    }

    template <typename T>
    inline std::vector<T> Interpolate(const std::vector<T>& v1, const std::vector<T>& v2, const double ratio)
    {
        // Safety check ratio
        const double real_ratio = SafetyCheckUnitInterval(ratio);
        // Safety check inputs
        const size_t len = v1.size();
        if (len != v2.size())
        {
            std::cerr << "Vectors to interpolate are different sizes (" << v1.size() << " versus " << v2.size() << ")" << std::endl;
            return std::vector<T>();
        }
        // Interpolate
        // This is the numerically stable version, rather than  (p1 + (p2 - p1) * real_ratio)
        std::vector<T> interped(len, 0);
        for (size_t idx = 0; idx < len; idx++)
        {
            interped[idx] = ((v1[idx] * (1.0 - real_ratio)) + (v2[idx] * real_ratio));
        }
        return interped;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Distance functions
    ////////////////////////////////////////////////////////////////////////////

    inline double SquaredDistance(const std::vector<double>& p1, const std::vector<double>& p2)
    {
        if (p1.size() == p2.size())
        {
            double distance = 0.0;
            for (size_t idx = 0; idx < p1.size(); idx++)
            {
                distance += (p2[idx] - p1[idx]) * (p2[idx] - p1[idx]);
            }
            return distance;
        }
        else
        {
            return INFINITY;
        }
    }

    inline double Distance(const std::vector<double>& p1, const std::vector<double>& p2)
    {
        if (p1.size() == p2.size())
        {
            return sqrt(SquaredDistance(p1, p2));
        }
        else
        {
            return INFINITY;
        }
    }

    inline double ContinuousRevoluteSignedDistance(const double p1, const double p2)
    {
        // Safety check args
        const double real_p1 = EnforceContinuousRevoluteBounds(p1);
        const double real_p2 = EnforceContinuousRevoluteBounds(p2);
        const double raw_distance = real_p2 - real_p1;
        if ((raw_distance <= -M_PI) || (raw_distance > M_PI))
        {
            if (raw_distance <= -M_PI)
            {
                return (-(2.0 * M_PI) - raw_distance);
            }
            else if (raw_distance > M_PI)
            {
                return ((2.0 * M_PI) - raw_distance);
            }
            else
            {
                return raw_distance;
            }
        }
        else
        {
            return raw_distance;
        }
    }

    inline double ContinuousRevoluteDistance(const double p1, const double p2)
    {
        return std::abs(ContinuousRevoluteSignedDistance(p1, p2));
    }

    inline double AddContinuousRevoluteValues(const double start, const double change)
    {
        return EnforceContinuousRevoluteBounds(start + change);
    }

    inline double GetContinuousRevoluteRange(const double start, const double end)
    {
        const double raw_range = ContinuousRevoluteSignedDistance(start, end);
        if (raw_range >= 0.0)
        {
            return raw_range;
        }
        else
        {
            return (2.0 * M_PI) + raw_range;
        }
    }

    inline bool CheckInContinuousRevoluteRange(const double start, const double range, const double val)
    {
        const double real_val = EnforceContinuousRevoluteBounds(val);
        const double real_start = EnforceContinuousRevoluteBounds(start);
        const double delta = ContinuousRevoluteSignedDistance(real_start, real_val);
        if (delta >= 0.0)
        {
            if (delta <= range)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            const double real_delta = (2.0 * M_PI) + delta;
            if (real_delta <= range)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    inline bool CheckInContinuousRevoluteBounds(const double start, const double end, const double val)
    {
        const double range = GetContinuousRevoluteRange(start, end);
        return CheckInContinuousRevoluteRange(start, range, val);
    }

    // DistanceFn must match the following interface: std::function<double(const T&, const T&)>
    template<typename T, class DistanceFn, typename Alloc = std::allocator<T>>
    inline double CalculateTotalDistance(const std::vector<T, Alloc>& path, const DistanceFn& distance_fn)
    {
        double total_dist = 0;
        for (size_t path_idx = 0; path_idx + 1 < path.size(); path_idx++)
        {
            const double delta = distance_fn(path[path_idx], path[path_idx + 1]);
            total_dist += delta;
        }
        return total_dist;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Averaging functions
    // Numerically more stable averages taken from http://people.ds.cam.ac.uk/fanf2/hermes/doc/antiforgery/stats.pdf
    ////////////////////////////////////////////////////////////////////////////

    inline double AverageStdVectorDouble(
            const std::vector<double>& values,
            const std::vector<double>& weights = std::vector<double>())
    {
        // Get the weights
        assert(values.size() > 0);
        assert((weights.size() == values.size()) || (weights.size() == 0));
        const bool use_weights = (weights.size() != 0);
        // Find the first element with non-zero weight
        size_t starting_idx = 0;
        while (starting_idx < weights.size() && weights[starting_idx] == 0.0)
        {
            starting_idx++;
        }
        // If all weights are zero, result is undefined
        assert(starting_idx < values.size());
        // Start the recursive definition with the base case
        double average = values[starting_idx];
        const double starting_weight = use_weights ? std::abs(weights[starting_idx]) : 1.0;
        assert(starting_weight > 0.0);
        double weights_running_sum = starting_weight;
        // Do the weighted averaging on the rest of the vectors
        for (size_t idx = starting_idx + 1; idx < values.size(); idx++)
        {
            const double weight = use_weights ? std::abs(weights[idx]) : 1.0;
            weights_running_sum += weight;
            const double effective_weight = weight / weights_running_sum;
            const double prev_average = average;
            const double current = values[idx];
            average = prev_average + (effective_weight * (current - prev_average));
        }
        return average;
    }

    inline double ComputeStdDevStdVectorDouble(const std::vector<double>& values, const double mean)
    {
        assert(values.size() > 0);
        if (values.size() == 1)
        {
            return 0.0;
        }
        else
        {
            const double inv_n_minus_1 = 1.0 / (double)(values.size() - 1);
            double stddev_sum = 0.0;
            for (size_t idx = 0; idx < values.size(); idx++)
            {
                const double delta = values[idx] - mean;
                stddev_sum += (delta * delta);
            }
            return std::sqrt(stddev_sum * inv_n_minus_1);
        }
    }

    inline double ComputeStdDevStdVectorDouble(const std::vector<double>& values)
    {
        const double mean = AverageStdVectorDouble(values);
        return ComputeStdDevStdVectorDouble(values, mean);
    }

    /*
     * This function does not actually deal with the continuous revolute space correctly,
     * it just assumes a normal real Euclidean space
     */
    inline double AverageContinuousRevolute(
            const std::vector<double>& angles,
            const std::vector<double>& weights = std::vector<double>())
    {
        return AverageStdVectorDouble(angles, weights);
    }
}

#endif //ARC_UTILITIES_MATH_HELPERS_HPP
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/options/wifi_config_view.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/options/network_config_view.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
#include "views/controls/button/image_button.h"
#include "views/controls/button/native_button.h"
#include "views/controls/label.h"
#include "views/grid_layout.h"
#include "views/standard_layout.h"
#include "views/window/window.h"

namespace chromeos {

// The width of the password field.
const int kPasswordWidth = 150;

WifiConfigView::WifiConfigView(NetworkConfigView* parent,
                               const WifiNetwork* wifi)
    : parent_(parent),
      other_network_(false),
      can_login_(false),
      wifi_(new WifiNetwork(*wifi)),
      ssid_textfield_(NULL),
      identity_textfield_(NULL),
      certificate_browse_button_(NULL),
      certificate_path_(),
      passphrase_textfield_(NULL),
      passphrase_visible_button_(NULL),
      autoconnect_checkbox_(NULL) {
  Init();
}

WifiConfigView::WifiConfigView(NetworkConfigView* parent)
    : parent_(parent),
      other_network_(true),
      can_login_(false),
      wifi_(NULL),
      ssid_textfield_(NULL),
      identity_textfield_(NULL),
      certificate_browse_button_(NULL),
      certificate_path_(),
      passphrase_textfield_(NULL),
      passphrase_visible_button_(NULL),
      autoconnect_checkbox_(NULL) {
  Init();
}

WifiConfigView::~WifiConfigView() {
}

void WifiConfigView::UpdateCanLogin(void) {
  bool can_login = true;
  if (other_network_) {
    // Since the user can try to connect to a non-encrypted hidden network,
    // only enforce ssid is non-empty.
    can_login = !ssid_textfield_->text().empty();
  } else {
    // Connecting to an encrypted network
    if (passphrase_textfield_ != NULL) {
      // if the network requires a passphrase, make sure it is non empty.
      can_login &= !passphrase_textfield_->text().empty();
    }
    if (identity_textfield_ != NULL) {
      // If we have an identity field, we can login if we have a non empty
      // identity and a certificate path
      can_login &= !identity_textfield_->text().empty() &&
          !certificate_path_.empty();
    }
  }

  // Update the login button enable/disable state if can_login_ changes.
  if (can_login != can_login_) {
    can_login_ = can_login;
    parent_->GetDialogClientView()->UpdateDialogButtons();
  }
}

void WifiConfigView::UpdateCanViewPassword() {
  if (passphrase_visible_button_ &&
      !passphrase_visible_button_->IsVisible() &&
      passphrase_textfield_->text().empty()) {
    // Once initial password has been deleted, it's safe to show field content.
    passphrase_visible_button_->SetVisible(true);
  }
}

void WifiConfigView::ContentsChanged(views::Textfield* sender,
                                     const string16& new_contents) {
  UpdateCanLogin();
  UpdateCanViewPassword();
}

bool WifiConfigView::HandleKeystroke(
    views::Textfield* sender,
    const views::Textfield::Keystroke& keystroke) {
  if (sender == passphrase_textfield_ &&
      keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
    parent_->GetDialogClientView()->AcceptWindow();
  }
  return false;
}

void WifiConfigView::ButtonPressed(views::Button* sender,
                                   const views::Event& event) {
  if (sender == passphrase_visible_button_) {
    if (passphrase_textfield_)
      passphrase_textfield_->SetPassword(!passphrase_textfield_->IsPassword());
  } else if (sender == certificate_browse_button_) {
    select_file_dialog_ = SelectFileDialog::Create(this);
    select_file_dialog_->set_browser_mode(parent_->is_browser_mode());
    select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
                                    string16(), FilePath(), NULL, 0,
                                    std::string(),
                                    parent_->is_browser_mode() ?
                                        NULL :
                                        parent_->GetNativeWindow(),
                                    NULL);
  } else {
    NOTREACHED();
  }
}

void WifiConfigView::FileSelected(const FilePath& path,
                                   int index, void* params) {
  certificate_path_ = path.value();
  if (certificate_browse_button_)
    certificate_browse_button_->SetLabel(path.BaseName().ToWStringHack());
  UpdateCanLogin();  // TODO(njw) Check if the passphrase decrypts the key.
}

bool WifiConfigView::Login() {
  std::string identity_string;
  if (identity_textfield_ != NULL) {
    identity_string = UTF16ToUTF8(identity_textfield_->text());
  }
  if (other_network_) {
    CrosLibrary::Get()->GetNetworkLibrary()->ConnectToWifiNetwork(
        GetSSID(), GetPassphrase(),
        identity_string, certificate_path_,
        autoconnect_checkbox_ ? autoconnect_checkbox_->checked() : true);
  } else {
    Save();
    CrosLibrary::Get()->GetNetworkLibrary()->ConnectToWifiNetwork(
        wifi_.get(), GetPassphrase(),
        identity_string, certificate_path_);
  }
  return true;
}

bool WifiConfigView::Save() {
  // Save password and auto-connect here.
  if (!other_network_) {
    bool changed = false;

    if (autoconnect_checkbox_) {
      bool auto_connect = autoconnect_checkbox_->checked();
      if (auto_connect != wifi_->auto_connect()) {
        wifi_->set_auto_connect(auto_connect);
        changed = true;
      }
    }

    if (passphrase_textfield_) {
      const std::string& passphrase =
          UTF16ToUTF8(passphrase_textfield_->text());
      if (passphrase != wifi_->passphrase()) {
        wifi_->set_passphrase(passphrase);
        changed = true;
      }
    }

    if (changed)
      CrosLibrary::Get()->GetNetworkLibrary()->SaveWifiNetwork(wifi_.get());
  }
  return true;
}

const std::string WifiConfigView::GetSSID() const {
  std::string result;
  if (ssid_textfield_ != NULL)
    result = UTF16ToUTF8(ssid_textfield_->text());
  return result;
}

const std::string WifiConfigView::GetPassphrase() const {
  std::string result;
  if (passphrase_textfield_ != NULL)
    result = UTF16ToUTF8(passphrase_textfield_->text());
  return result;
}

void WifiConfigView::FocusFirstField() {
  if (ssid_textfield_)
    ssid_textfield_->RequestFocus();
  else if (identity_textfield_)
    identity_textfield_->RequestFocus();
  else if (passphrase_textfield_)
    passphrase_textfield_->RequestFocus();
}

void WifiConfigView::Init() {
  views::GridLayout* layout = CreatePanelGridLayout(this);
  SetLayoutManager(layout);

  int column_view_set_id = 0;
  views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id);
  // Label
  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  // Textfield
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, kPasswordWidth);
  // Password visible button
  column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);

  layout->StartRow(0, column_view_set_id);
  layout->AddView(new views::Label(l10n_util::GetString(
      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_ID)));
  if (other_network_) {
    ssid_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
    ssid_textfield_->SetController(this);
    layout->AddView(ssid_textfield_);
  } else {
    views::Label* label = new views::Label(ASCIIToWide(wifi_->name()));
    label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    layout->AddView(label);
  }
  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);

  // Loaded certificates (i.e. stored in a pkcs11 device) do not require
  // a passphrase.
  bool certificate_loaded = false;

  // Add ID and cert password if we're using 802.1x
  // XXX we're cheating and assuming 802.1x means EAP-TLS - not true
  // in general, but very common. WPA Supplicant doesn't report the
  // EAP type because it's unknown until the process begins, and we'd
  // need some kind of callback.
  if (wifi_->encrypted() && wifi_->encryption() == SECURITY_8021X) {
    layout->StartRow(0, column_view_set_id);
    layout->AddView(new views::Label(l10n_util::GetString(
        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_IDENTITY)));
    identity_textfield_ = new views::Textfield(
        views::Textfield::STYLE_DEFAULT);
    identity_textfield_->SetController(this);
    if (!wifi_->identity().empty())
      identity_textfield_->SetText(UTF8ToUTF16(wifi_->identity()));
    layout->AddView(identity_textfield_);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
    layout->StartRow(0, column_view_set_id);
    layout->AddView(new views::Label(l10n_util::GetString(
        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT)));
    if (!wifi_->cert_path().empty()) {
      certificate_path_ = wifi_->cert_path();
      certificate_loaded = wifi_->IsCertificateLoaded();
    }
    if (certificate_loaded) {
      std::wstring label = l10n_util::GetString(
          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_INSTALLED);
      views::Label* cert_text = new views::Label(label);
      cert_text->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
      layout->AddView(cert_text);
    } else {
      std::wstring label;
      if (!certificate_path_.empty())
        label = UTF8ToWide(certificate_path_);
      else
        label = l10n_util::GetString(
            IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_BUTTON);
      certificate_browse_button_ = new views::NativeButton(this, label);
      layout->AddView(certificate_browse_button_);
    }
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }

  // Add passphrase if other_network or wifi is encrypted.
  if (other_network_ || (wifi_->encrypted() && !certificate_loaded)) {
    layout->StartRow(0, column_view_set_id);
    int label_text_id;
    if (wifi_->encryption() == SECURITY_8021X)
      label_text_id =
          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PRIVATE_KEY_PASSWORD;
    else
      label_text_id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PASSPHRASE;
    layout->AddView(new views::Label(l10n_util::GetString(label_text_id)));
    passphrase_textfield_ = new views::Textfield(
        views::Textfield::STYLE_PASSWORD);
    passphrase_textfield_->SetController(this);
    if (!wifi_->passphrase().empty())
      passphrase_textfield_->SetText(UTF8ToUTF16(wifi_->passphrase()));
    layout->AddView(passphrase_textfield_);
    // Password visible button.
    passphrase_visible_button_ = new views::ImageButton(this);
    passphrase_visible_button_->SetImage(views::ImageButton::BS_NORMAL,
        ResourceBundle::GetSharedInstance().
        GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE));
    passphrase_visible_button_->SetImageAlignment(
        views::ImageButton::ALIGN_CENTER, views::ImageButton::ALIGN_MIDDLE);
    // Disable viewing password by unauthenticated user.
    if (!wifi_->passphrase().empty() &&
        chromeos::UserManager::Get()->logged_in_user().email().empty()) {
      passphrase_visible_button_->SetVisible(false);
    }
    layout->AddView(passphrase_visible_button_);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }

  // If there's an error, add an error message label.
  // Right now, only displaying bad_passphrase and bad_wepkey errors.
  if (wifi_->error() == ERROR_BAD_PASSPHRASE ||
      wifi_->error() == ERROR_BAD_WEPKEY) {
    layout->StartRow(0, column_view_set_id);
    layout->SkipColumns(1);
    int id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_PASSPHRASE;
    if (wifi_->error() == ERROR_BAD_WEPKEY)
      id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_WEPKEY;
    views::Label* label_error = new views::Label(l10n_util::GetString(id));
    label_error->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    label_error->SetColor(SK_ColorRED);
    layout->AddView(label_error);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }

  // Autoconnect checkbox
  // Only show if this network is already remembered (a favorite).
  if (wifi_->favorite()) {
    autoconnect_checkbox_ = new views::Checkbox(l10n_util::GetString(
        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_AUTO_CONNECT));
    // For other network, default to autoconnect.
    bool autoconnect = other_network_ || wifi_->auto_connect();
    autoconnect_checkbox_->SetChecked(autoconnect);
    layout->StartRow(0, column_view_set_id);
    layout->AddView(autoconnect_checkbox_, 3, 1);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }
}

}  // namespace chromeos
<commit_msg>Fixed crash in Add Network dialog.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/options/wifi_config_view.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/options/network_config_view.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
#include "views/controls/button/image_button.h"
#include "views/controls/button/native_button.h"
#include "views/controls/label.h"
#include "views/grid_layout.h"
#include "views/standard_layout.h"
#include "views/window/window.h"

namespace chromeos {

// The width of the password field.
const int kPasswordWidth = 150;

WifiConfigView::WifiConfigView(NetworkConfigView* parent,
                               const WifiNetwork* wifi)
    : parent_(parent),
      other_network_(false),
      can_login_(false),
      wifi_(new WifiNetwork(*wifi)),
      ssid_textfield_(NULL),
      identity_textfield_(NULL),
      certificate_browse_button_(NULL),
      certificate_path_(),
      passphrase_textfield_(NULL),
      passphrase_visible_button_(NULL),
      autoconnect_checkbox_(NULL) {
  Init();
}

WifiConfigView::WifiConfigView(NetworkConfigView* parent)
    : parent_(parent),
      other_network_(true),
      can_login_(false),
      ssid_textfield_(NULL),
      identity_textfield_(NULL),
      certificate_browse_button_(NULL),
      certificate_path_(),
      passphrase_textfield_(NULL),
      passphrase_visible_button_(NULL),
      autoconnect_checkbox_(NULL) {
  Init();
}

WifiConfigView::~WifiConfigView() {
}

void WifiConfigView::UpdateCanLogin(void) {
  bool can_login = true;
  if (other_network_) {
    // Since the user can try to connect to a non-encrypted hidden network,
    // only enforce ssid is non-empty.
    can_login = !ssid_textfield_->text().empty();
  } else {
    // Connecting to an encrypted network
    if (passphrase_textfield_ != NULL) {
      // if the network requires a passphrase, make sure it is non empty.
      can_login &= !passphrase_textfield_->text().empty();
    }
    if (identity_textfield_ != NULL) {
      // If we have an identity field, we can login if we have a non empty
      // identity and a certificate path
      can_login &= !identity_textfield_->text().empty() &&
          !certificate_path_.empty();
    }
  }

  // Update the login button enable/disable state if can_login_ changes.
  if (can_login != can_login_) {
    can_login_ = can_login;
    parent_->GetDialogClientView()->UpdateDialogButtons();
  }
}

void WifiConfigView::UpdateCanViewPassword() {
  if (passphrase_visible_button_ &&
      !passphrase_visible_button_->IsVisible() &&
      passphrase_textfield_->text().empty()) {
    // Once initial password has been deleted, it's safe to show field content.
    passphrase_visible_button_->SetVisible(true);
  }
}

void WifiConfigView::ContentsChanged(views::Textfield* sender,
                                     const string16& new_contents) {
  UpdateCanLogin();
  UpdateCanViewPassword();
}

bool WifiConfigView::HandleKeystroke(
    views::Textfield* sender,
    const views::Textfield::Keystroke& keystroke) {
  if (sender == passphrase_textfield_ &&
      keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
    parent_->GetDialogClientView()->AcceptWindow();
  }
  return false;
}

void WifiConfigView::ButtonPressed(views::Button* sender,
                                   const views::Event& event) {
  if (sender == passphrase_visible_button_) {
    if (passphrase_textfield_)
      passphrase_textfield_->SetPassword(!passphrase_textfield_->IsPassword());
  } else if (sender == certificate_browse_button_) {
    select_file_dialog_ = SelectFileDialog::Create(this);
    select_file_dialog_->set_browser_mode(parent_->is_browser_mode());
    select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
                                    string16(), FilePath(), NULL, 0,
                                    std::string(),
                                    parent_->is_browser_mode() ?
                                        NULL :
                                        parent_->GetNativeWindow(),
                                    NULL);
  } else {
    NOTREACHED();
  }
}

void WifiConfigView::FileSelected(const FilePath& path,
                                   int index, void* params) {
  certificate_path_ = path.value();
  if (certificate_browse_button_)
    certificate_browse_button_->SetLabel(path.BaseName().ToWStringHack());
  UpdateCanLogin();  // TODO(njw) Check if the passphrase decrypts the key.
}

bool WifiConfigView::Login() {
  std::string identity_string;
  if (identity_textfield_ != NULL) {
    identity_string = UTF16ToUTF8(identity_textfield_->text());
  }
  if (other_network_) {
    CrosLibrary::Get()->GetNetworkLibrary()->ConnectToWifiNetwork(
        GetSSID(), GetPassphrase(),
        identity_string, certificate_path_,
        autoconnect_checkbox_ ? autoconnect_checkbox_->checked() : true);
  } else {
    Save();
    CrosLibrary::Get()->GetNetworkLibrary()->ConnectToWifiNetwork(
        wifi_.get(), GetPassphrase(),
        identity_string, certificate_path_);
  }
  return true;
}

bool WifiConfigView::Save() {
  // Save password and auto-connect here.
  if (!other_network_) {
    bool changed = false;

    if (autoconnect_checkbox_) {
      bool auto_connect = autoconnect_checkbox_->checked();
      if (auto_connect != wifi_->auto_connect()) {
        wifi_->set_auto_connect(auto_connect);
        changed = true;
      }
    }

    if (passphrase_textfield_) {
      const std::string& passphrase =
          UTF16ToUTF8(passphrase_textfield_->text());
      if (passphrase != wifi_->passphrase()) {
        wifi_->set_passphrase(passphrase);
        changed = true;
      }
    }

    if (changed)
      CrosLibrary::Get()->GetNetworkLibrary()->SaveWifiNetwork(wifi_.get());
  }
  return true;
}

const std::string WifiConfigView::GetSSID() const {
  std::string result;
  if (ssid_textfield_ != NULL)
    result = UTF16ToUTF8(ssid_textfield_->text());
  return result;
}

const std::string WifiConfigView::GetPassphrase() const {
  std::string result;
  if (passphrase_textfield_ != NULL)
    result = UTF16ToUTF8(passphrase_textfield_->text());
  return result;
}

void WifiConfigView::FocusFirstField() {
  if (ssid_textfield_)
    ssid_textfield_->RequestFocus();
  else if (identity_textfield_)
    identity_textfield_->RequestFocus();
  else if (passphrase_textfield_)
    passphrase_textfield_->RequestFocus();
}

void WifiConfigView::Init() {
  views::GridLayout* layout = CreatePanelGridLayout(this);
  SetLayoutManager(layout);

  int column_view_set_id = 0;
  views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id);
  // Label
  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  // Textfield
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, kPasswordWidth);
  // Password visible button
  column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);

  layout->StartRow(0, column_view_set_id);
  layout->AddView(new views::Label(l10n_util::GetString(
      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_ID)));
  if (other_network_) {
    ssid_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
    ssid_textfield_->SetController(this);
    layout->AddView(ssid_textfield_);
  } else {
    views::Label* label = new views::Label(ASCIIToWide(wifi_->name()));
    label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    layout->AddView(label);
  }
  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);

  // Loaded certificates (i.e. stored in a pkcs11 device) do not require
  // a passphrase.
  bool certificate_loaded = false;

  // Add ID and cert password if we're using 802.1x
  // XXX we're cheating and assuming 802.1x means EAP-TLS - not true
  // in general, but very common. WPA Supplicant doesn't report the
  // EAP type because it's unknown until the process begins, and we'd
  // need some kind of callback.
  if (wifi_.get() && wifi_->encrypted() &&
      wifi_->encryption() == SECURITY_8021X) {
    layout->StartRow(0, column_view_set_id);
    layout->AddView(new views::Label(l10n_util::GetString(
        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_IDENTITY)));
    identity_textfield_ = new views::Textfield(
        views::Textfield::STYLE_DEFAULT);
    identity_textfield_->SetController(this);
    if (!wifi_->identity().empty())
      identity_textfield_->SetText(UTF8ToUTF16(wifi_->identity()));
    layout->AddView(identity_textfield_);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
    layout->StartRow(0, column_view_set_id);
    layout->AddView(new views::Label(l10n_util::GetString(
        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT)));
    if (!wifi_->cert_path().empty()) {
      certificate_path_ = wifi_->cert_path();
      certificate_loaded = wifi_->IsCertificateLoaded();
    }
    if (certificate_loaded) {
      std::wstring label = l10n_util::GetString(
          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_INSTALLED);
      views::Label* cert_text = new views::Label(label);
      cert_text->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
      layout->AddView(cert_text);
    } else {
      std::wstring label;
      if (!certificate_path_.empty())
        label = UTF8ToWide(certificate_path_);
      else
        label = l10n_util::GetString(
            IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_BUTTON);
      certificate_browse_button_ = new views::NativeButton(this, label);
      layout->AddView(certificate_browse_button_);
    }
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }

  // Add passphrase if other_network or wifi is encrypted.
  if (other_network_ || (wifi_.get() && wifi_->encrypted() &&
                         !certificate_loaded)) {
    layout->StartRow(0, column_view_set_id);
    int label_text_id;
    if (wifi_.get() && wifi_->encryption() == SECURITY_8021X)
      label_text_id =
          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PRIVATE_KEY_PASSWORD;
    else
      label_text_id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PASSPHRASE;
    layout->AddView(new views::Label(l10n_util::GetString(label_text_id)));
    passphrase_textfield_ = new views::Textfield(
        views::Textfield::STYLE_PASSWORD);
    passphrase_textfield_->SetController(this);
    if (wifi_.get() && !wifi_->passphrase().empty())
      passphrase_textfield_->SetText(UTF8ToUTF16(wifi_->passphrase()));
    layout->AddView(passphrase_textfield_);
    // Password visible button.
    passphrase_visible_button_ = new views::ImageButton(this);
    passphrase_visible_button_->SetImage(views::ImageButton::BS_NORMAL,
        ResourceBundle::GetSharedInstance().
        GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE));
    passphrase_visible_button_->SetImageAlignment(
        views::ImageButton::ALIGN_CENTER, views::ImageButton::ALIGN_MIDDLE);
    // Disable viewing password by unauthenticated user.
    if (wifi_.get() && !wifi_->passphrase().empty() &&
        chromeos::UserManager::Get()->logged_in_user().email().empty()) {
      passphrase_visible_button_->SetVisible(false);
    }
    layout->AddView(passphrase_visible_button_);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }

  // If there's an error, add an error message label.
  // Right now, only displaying bad_passphrase and bad_wepkey errors.
  if (wifi_.get() && (wifi_->error() == ERROR_BAD_PASSPHRASE ||
      wifi_->error() == ERROR_BAD_WEPKEY)) {
    layout->StartRow(0, column_view_set_id);
    layout->SkipColumns(1);
    int id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_PASSPHRASE;
    if (wifi_->error() == ERROR_BAD_WEPKEY)
      id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_WEPKEY;
    views::Label* label_error = new views::Label(l10n_util::GetString(id));
    label_error->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    label_error->SetColor(SK_ColorRED);
    layout->AddView(label_error);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }

  // Autoconnect checkbox
  // Only show if this network is already remembered (a favorite).
  if (wifi_.get() && wifi_->favorite()) {
    autoconnect_checkbox_ = new views::Checkbox(l10n_util::GetString(
        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_AUTO_CONNECT));
    // For other network, default to autoconnect.
    bool autoconnect = other_network_ || wifi_->auto_connect();
    autoconnect_checkbox_->SetChecked(autoconnect);
    layout->StartRow(0, column_view_set_id);
    layout->AddView(autoconnect_checkbox_, 3, 1);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }
}

}  // namespace chromeos
<|endoftext|>


<commit_before><commit_msg>Re-disable ExtensionApiTest.Tabs (flakey)<commit_after><|endoftext|>