text:
#pragma once

#include <string>
#include <cstring>
#include <utility>
#include <vector>
#include <memory>
#include <cstdio>
#include <functional>
#include "utilities\FileSystem.h"
#include "utilities\Log.h"
#include "utilities\String.h"
#include "utilities\Utf8String.h"
#include "tinyxml2\tinyxml2.h"
#include "Format.h"
#include "Item.h"
#include "Language.h"
#include "Options.h"
#include "Path.h"
#include "Preset.h"
#include "Settings.h"
#include "Strings.h"
#include "Tool.h"

#define VALIDATE(value) if (!value) return false

namespace config::xml
{
    typedef tinyxml2::XMLNode XmlNode;
    typedef tinyxml2::XMLElement XmlElement;
    typedef tinyxml2::XMLDocument XmlDocumnent;

    class XmlDoc
    {
    protected:
        XmlDocumnent & m_Document;
    public:
        XmlDoc(XmlDocumnent &doc) : m_Document(doc) { }
        virtual ~XmlDoc() { }
    public:
        static const char* GetRootName(XmlDocumnent &doc)
        {
            auto root = doc.RootElement();
            if (root != nullptr)
                return root->Name();
            return nullptr;
        }
    public:
        static void Create(XmlDocumnent & doc)
        {
            doc.LinkEndChild(doc.NewDeclaration("xml version=\"1.0\" encoding=\"UTF-8\""));
        }
        static bool Open(const std::wstring& szFileName, XmlDocumnent & doc)
        {
            FILE *fs = nullptr;
            errno_t error = _wfopen_s(&fs, szFileName.c_str(), L"rb");
            if (error != 0 || fs == nullptr)
                return false;

            tinyxml2::XMLError result = doc.LoadFile(fs);
            fclose(fs);

            return result == tinyxml2::XMLError::XML_SUCCESS;
        }
        static bool Parse(const char* xml, XmlDocumnent & doc)
        {
            tinyxml2::XMLError result = doc.Parse(xml);
            return result == tinyxml2::XMLError::XML_SUCCESS;
        }
        static bool Save(const std::wstring& szFileName, XmlDocumnent & doc)
        {
            FILE *fs = nullptr;
            errno_t error = _wfopen_s(&fs, szFileName.c_str(), L"wt");
            if (error != 0 || fs == nullptr)
                return false;

            fputc(0xefU, fs);
            fputc(0xbbU, fs);
            fputc(0xbfU, fs);

            tinyxml2::XMLPrinter printer(fs);
            doc.Print(&printer);

            fclose(fs);
            return true;
        }
    public:
        static inline const std::wstring ToString(const char *pszUtf8)
        {
            if (pszUtf8 == nullptr)
                return std::wstring();
            if (strlen(pszUtf8) == 0)
                return std::wstring();
            return std::move(util::ToUnicode(pszUtf8));
        }
        static inline int ToInt(const char *pszUtf8)
        {
            return std::move(std::stoi(pszUtf8));
        }
        static inline size_t ToUInt(const char *pszUtf8)
        {
            return std::move(std::stoul(pszUtf8));
        }
        static inline unsigned __int64 ToUInt64(const char *pszUtf8)
        {
            return std::move(std::strtoull(pszUtf8, nullptr, 10));
        }
        static inline bool ToBool(const char *pszUtf8)
        {
            return _stricmp(pszUtf8, u8"true") == 0;
        }
        static inline std::string IntToString(const int nValue)
        {
            return std::move(std::to_string(nValue));
        }
        static inline std::string SizeToString(const size_t nValue)
        {
            return std::move(std::to_string(nValue));
        }
        static inline std::string UInt64ToString(const unsigned __int64 nValue)
        {
            return std::move(std::to_string(nValue));
        }
        static inline const char * BoolToString(const bool bValue)
        {
            return bValue ? u8"true" : u8"false";
        }
    public:
        inline bool GetAttributeValueString(const XmlElement *element, const char *name, std::wstring *value)
        {
            const char *pszResult = element->Attribute(name);
            if (pszResult != nullptr)
            {
                (*value) = std::move(ToString(pszResult));
                return true;
            }
            return false;
        }
        inline bool GetAttributeValueInt(const XmlElement *element, const char *name, int *value)
        {
            const char *pszResult = element->Attribute(name);
            if (pszResult != nullptr)
            {
                (*value) = ToInt(pszResult);
                return true;
            }
            return false;
        }
        inline bool GetAttributeValueSizeT(const XmlElement *element, const char *name, size_t *value)
        {
            const char *pszResult = element->Attribute(name);
            if (pszResult != nullptr)
            {
                (*value) = ToUInt(pszResult);
                return true;
            }
            return false;
        }
        inline bool GetAttributeValueUInt64(const XmlElement *element, const char *name, unsigned __int64 *value)
        {
            const char *pszResult = element->Attribute(name);
            if (pszResult != nullptr)
            {
                (*value) = ToUInt64(pszResult);
                return true;
            }
            return false;
        }
        inline bool GetAttributeValueBool(const XmlElement *element, const char *name, bool *value)
        {
            const char *pszResult = element->Attribute(name);
            if (pszResult != nullptr)
            {
                (*value) = ToBool(pszResult);
                return true;
            }
            return false;
        }
    public:
        inline void SetAttributeValueString(XmlElement *element, const char *name, const std::wstring& value)
        {
            element->SetAttribute(name, util::ToUtf8(value).c_str());
        }
        inline void SetAttributeValueInt(XmlElement *element, const char *name, const int &value)
        {
            element->SetAttribute(name, IntToString(value).c_str());
        }
        inline void SetAttributeValueSizeT(XmlElement *element, const char *name, const size_t &value)
        {
            element->SetAttribute(name, SizeToString(value).c_str());
        }
        inline void SetAttributeValueUInt64(XmlElement *element, const char *name, const unsigned __int64 &value)
        {
            element->SetAttribute(name, UInt64ToString(value).c_str());
        }
        inline void SetAttributeValueBool(XmlElement *element, const char *name, const bool &value)
        {
            element->SetAttribute(name, BoolToString(value));
        }
    public:
        inline bool GetChildValueString(const XmlElement *parent, const char *name, std::wstring *value)
        {
            auto element = parent->FirstChildElement(name);
            if (element != nullptr)
            {
                (*value) = std::move(ToString(element->GetText()));
                return true;
            }
            return false;
        }
        inline bool GetChildValueInt(const XmlElement *parent, const char *name, int *value)
        {
            auto element = parent->FirstChildElement(name);
            if (element != nullptr)
            {
                (*value) = ToInt(element->GetText());
                return true;
            }
            return false;
        }
        inline bool GetChildValueSizeT(const XmlElement *parent, const char *name, size_t *value)
        {
            auto element = parent->FirstChildElement(name);
            if (element != nullptr)
            {
                (*value) = ToUInt(element->GetText());
                return true;
            }
            return false;
        }
        inline bool GetChildValueUInt64(const XmlElement *parent, const char *name, unsigned __int64 *value)
        {
            auto element = parent->FirstChildElement(name);
            if (element != nullptr)
            {
                (*value) = ToUInt64(element->GetText());
                return true;
            }
            return false;
        }
        inline bool GetChildValueBool(const XmlElement *parent, const char *name, bool *value)
        {
            auto element = parent->FirstChildElement(name);
            if (element != nullptr)
            {
                (*value) = ToBool(element->GetText());
                return true;
            }
            return false;
        }
    public:
        inline void SetChildValueString(XmlElement *parent, const char *name, const std::wstring& value)
        {
            auto element = m_Document.NewElement(name);
            element->LinkEndChild(m_Document.NewText(util::ToUtf8(value).c_str()));
            parent->LinkEndChild(element);
        }
        inline void SetChildValueInt(XmlElement *parent, const char *name, const int &value)
        {
            auto element = m_Document.NewElement(name);
            element->LinkEndChild(m_Document.NewText(IntToString(value).c_str()));
            parent->LinkEndChild(element);
        }
        inline void SetChildValueSizeT(XmlElement *parent, const char *name, const size_t &value)
        {
            auto element = m_Document.NewElement(name);
            element->LinkEndChild(m_Document.NewText(SizeToString(value).c_str()));
            parent->LinkEndChild(element);
        }
        inline void SetChildValueUInt64(XmlElement *parent, const char *name, const unsigned __int64 &value)
        {
            auto element = m_Document.NewElement(name);
            element->LinkEndChild(m_Document.NewText(UInt64ToString(value).c_str()));
            parent->LinkEndChild(element);
        }
        inline void SetChildValueBool(XmlElement *parent, const char *name, const bool &value)
        {
            auto element = m_Document.NewElement(name);
            element->LinkEndChild(m_Document.NewText(BoolToString(value)));
            parent->LinkEndChild(element);
        }
    public:
        inline XmlElement * NewElement(const char *name)
        {
            return m_Document.NewElement(name);
        }
        inline XmlElement* FirstChildElement(const char *name)
        {
            return m_Document.FirstChildElement(name);
        }
        inline XmlNode* LinkEndChild(XmlNode* node)
        {
            return m_Document.LinkEndChild(node);
        }
    public:
        void Create()
        {
            XmlDoc::Create(m_Document);
        }
        bool Open(const std::wstring& szFileName)
        {
            return XmlDoc::Open(szFileName, m_Document);
        }
        bool Save(const std::wstring& szFileName)
        {
            return XmlDoc::Save(szFileName, m_Document);
        }
    };

    class XmlOptions : public XmlDoc
    {
    public:
        XmlOptions(XmlDocumnent &doc) : XmlDoc(doc) { }
        virtual ~XmlOptions() { }
    public:
        bool GetOptions(const XmlElement *element, config::COptions &m_Options)
        {
            GetChildValueString(element, "SelectedLanguage", &m_Options.szSelectedLanguage);
            GetChildValueSizeT(element, "SelectedFormat", &m_Options.nSelectedFormat);
            GetChildValueString(element, "OutputPath", &m_Options.szOutputPath);
            GetChildValueBool(element, "DeleteSourceFiles", &m_Options.bDeleteSourceFiles);
            GetChildValueBool(element, "RecurseChecked", &m_Options.bRecurseChecked);
            GetChildValueBool(element, "ShutdownWhenFinished", &m_Options.bShutdownWhenFinished);
            GetChildValueBool(element, "DoNotSaveConfiguration", &m_Options.bDoNotSaveConfiguration);
            GetChildValueBool(element, "DeleteOnErrors", &m_Options.bDeleteOnErrors);
            GetChildValueBool(element, "StopOnErrors", &m_Options.bStopOnErrors);
            GetChildValueBool(element, "HideConsoleWindow", &m_Options.bHideConsoleWindow);
            GetChildValueBool(element, "TryToFindDecoder", &m_Options.bTryToFindDecoder);
            GetChildValueBool(element, "EnsureItemIsVisible", &m_Options.bEnsureItemIsVisible);
            GetChildValueBool(element, "ValidateInputFiles", &m_Options.bValidateInputFiles);
            GetChildValueBool(element, "OverwriteExistingFiles", &m_Options.bOverwriteExistingFiles);
            GetChildValueBool(element, "RenameExistingFiles", &m_Options.bRenameExistingFiles);
            GetChildValueInt(element, "RenameExistingFilesLimit", &m_Options.nRenameExistingFilesLimit);
            GetChildValueBool(element, "TryToDownloadTools", &m_Options.bTryToDownloadTools);
            GetChildValueInt(element, "ThreadCount", &m_Options.nThreadCount);
            GetChildValueString(element, "OutputBrowse", &m_Options.szOutputBrowse);
            GetChildValueString(element, "DirectoryBrowse", &m_Options.szDirectoryBrowse);
            GetChildValueString(element, "MainWindowResize", &m_Options.szMainWindowResize);
            GetChildValueString(element, "FileListColumns", &m_Options.szFileListColumns);
            GetChildValueString(element, "PathsDialogResize", &m_Options.szPathsDialogResize);
            GetChildValueString(element, "PathsListColumns", &m_Options.szPathsListColumns);
            GetChildValueString(element, "PresetsDialogResize", &m_Options.szPresetsDialogResize);
            GetChildValueString(element, "PresetsListColumns", &m_Options.szPresetsListColumns);
            GetChildValueString(element, "FormatsDialogResize", &m_Options.szFormatsDialogResize);
            GetChildValueString(element, "FormatsListColumns", &m_Options.szFormatsListColumns);
            GetChildValueString(element, "ToolsDialogResize", &m_Options.szToolsDialogResize);
            GetChildValueString(element, "ToolsListColumns", &m_Options.szToolsListColumns);
            return true;
        }
        void SetOptions(XmlElement *element, config::COptions &m_Options)
        {
            SetChildValueString(element, "SelectedLanguage", m_Options.szSelectedLanguage);
            SetChildValueSizeT(element, "SelectedFormat", m_Options.nSelectedFormat);
            SetChildValueString(element, "OutputPath", m_Options.szOutputPath);
            SetChildValueBool(element, "DeleteSourceFiles", m_Options.bDeleteSourceFiles);
            SetChildValueBool(element, "RecurseChecked", m_Options.bRecurseChecked);
            SetChildValueBool(element, "ShutdownWhenFinished", m_Options.bShutdownWhenFinished);
            SetChildValueBool(element, "DoNotSaveConfiguration", m_Options.bDoNotSaveConfiguration);
            SetChildValueBool(element, "DeleteOnErrors", m_Options.bDeleteOnErrors);
            SetChildValueBool(element, "StopOnErrors", m_Options.bStopOnErrors);
            SetChildValueBool(element, "HideConsoleWindow", m_Options.bHideConsoleWindow);
            SetChildValueBool(element, "TryToFindDecoder", m_Options.bTryToFindDecoder);
            SetChildValueBool(element, "EnsureItemIsVisible", m_Options.bEnsureItemIsVisible);
            SetChildValueBool(element, "ValidateInputFiles", m_Options.bValidateInputFiles);
            SetChildValueBool(element, "OverwriteExistingFiles", m_Options.bOverwriteExistingFiles);
            SetChildValueBool(element, "RenameExistingFiles", m_Options.bRenameExistingFiles);
            SetChildValueInt(element, "RenameExistingFilesLimit", m_Options.nRenameExistingFilesLimit);
            SetChildValueBool(element, "TryToDownloadTools", m_Options.bTryToDownloadTools);
            SetChildValueInt(element, "ThreadCount", m_Options.nThreadCount);
            SetChildValueString(element, "OutputBrowse", m_Options.szOutputBrowse);
            SetChildValueString(element, "DirectoryBrowse", m_Options.szDirectoryBrowse);
            SetChildValueString(element, "MainWindowResize", m_Options.szMainWindowResize);
            SetChildValueString(element, "FileListColumns", m_Options.szFileListColumns);
            SetChildValueString(element, "PathsDialogResize", m_Options.szPathsDialogResize);
            SetChildValueString(element, "PathsListColumns", m_Options.szPathsListColumns);
            SetChildValueString(element, "PresetsDialogResize", m_Options.szPresetsDialogResize);
            SetChildValueString(element, "PresetsListColumns", m_Options.szPresetsListColumns);
            SetChildValueString(element, "FormatsDialogResize", m_Options.szFormatsDialogResize);
            SetChildValueString(element, "FormatsListColumns", m_Options.szFormatsListColumns);
            SetChildValueString(element, "ToolsDialogResize", m_Options.szToolsDialogResize);
            SetChildValueString(element, "ToolsListColumns", m_Options.szToolsListColumns);
        }
    public:
        bool GetOptions(config::COptions &m_Options)
        {
            auto element = this->FirstChildElement("Options");
            if (element != nullptr)
            {
                VALIDATE(this->GetOptions(element, m_Options));
                return true;
            }
            return false;
        }
        void SetOptions(config::COptions &m_Options)
        {
            auto pOptionsElem = this->NewElement("Options");
            this->LinkEndChild(pOptionsElem);
            this->SetOptions(pOptionsElem, m_Options);
        }
    };

    class XmlItems : public XmlDoc
    {
    public:
        XmlItems(XmlDocumnent &doc) : XmlDoc(doc) { }
        virtual ~XmlItems() { }
    public:
        bool GetPath(const XmlElement *element, config::CPath &m_Path)
        {
            VALIDATE(GetAttributeValueString(element, "path", &m_Path.szPath));
            VALIDATE(GetAttributeValueUInt64(element, "size", &m_Path.nSize));
            return true;
        }
        void SetPath(XmlElement *element, config::CPath &m_Path)
        {
            SetAttributeValueString(element, "path", m_Path.szPath);
            SetAttributeValueUInt64(element, "size", m_Path.nSize);
        }
        bool GetPaths(const XmlElement *parent, std::vector<config::CPath> &m_Paths)
        {
            auto element = parent->FirstChildElement("Path");
            if (element != nullptr)
            {
                for (element; element; element = element->NextSiblingElement())
                {
                    config::CPath path;
                    VALIDATE(this->GetPath(element, path));
                    m_Paths.emplace_back(std::move(path));
                }
                return true;
            }
            return false;
        }
        void SetPaths(XmlElement *parent, std::vector<config::CPath> &m_Paths)
        {
            size_t nPaths = m_Paths.size();
            for (size_t i = 0; i < nPaths; i++)
            {
                config::CPath& path = m_Paths[i];
                auto element = this->NewElement("Path");
                parent->LinkEndChild(element);
                this->SetPath(element, path);
            }
        }
    public:
        bool GetItem(const XmlElement *element, config::CItem &m_Item)
        {
            VALIDATE(GetAttributeValueInt(element, "id", &m_Item.nId));
            VALIDATE(GetAttributeValueUInt64(element, "size", &m_Item.nSize));
            VALIDATE(GetAttributeValueString(element, "name", &m_Item.szName));
            VALIDATE(GetAttributeValueString(element, "extension", &m_Item.szExtension));
            VALIDATE(GetAttributeValueString(element, "format", &m_Item.szFormatId));
            VALIDATE(GetAttributeValueSizeT(element, "preset", &m_Item.nPreset));
            VALIDATE(GetAttributeValueString(element, "options", &m_Item.szOptions));
            VALIDATE(GetAttributeValueBool(element, "checked", &m_Item.bChecked));
            VALIDATE(GetAttributeValueString(element, "time", &m_Item.szTime));
            VALIDATE(GetAttributeValueString(element, "status", &m_Item.szStatus));
            VALIDATE(this->GetPaths(element, m_Item.m_Paths));
            return true;
        }
        void SetItem(XmlElement *element, config::CItem &m_Item, int nId)
        {
            SetAttributeValueInt(element, "id", nId);
            SetAttributeValueUInt64(element, "size", m_Item.nSize);
            SetAttributeValueString(element, "name", m_Item.szName);
            SetAttributeValueString(element, "extension", m_Item.szExtension);
            SetAttributeValueString(element, "format", m_Item.szFormatId);
            SetAttributeValueSizeT(element, "preset", m_Item.nPreset);
            SetAttributeValueString(element, "options", m_Item.szOptions);
            SetAttributeValueBool(element, "checked", m_Item.bChecked);
            SetAttributeValueString(element, "time", m_Item.szTime);
            SetAttributeValueString(element, "status", m_Item.szStatus);
            this->SetPaths(element, m_Item.m_Paths);
        }
        bool GetItems(const XmlElement *parent, std::vector<config::CItem> &m_Items)
        {
            auto element = parent->FirstChildElement("Item");
            if (element != nullptr)
            {
                for (element; element; element = element->NextSiblingElement())
                {
                    config::CItem item;
                    VALIDATE(this->GetItem(element, item));
                    m_Items.emplace_back(std::move(item));
                }
                return true;
            }
            return false;
        }
        void SetItems(XmlElement *parent, std::vector<config::CItem> &m_Items)
        {
            size_t nItems = m_Items.size();
            for (size_t i = 0; i < nItems; i++)
            {
                config::CItem& item = m_Items[i];
                auto element = this->NewElement("Item");
                parent->LinkEndChild(element);
                this->SetItem(element, item, i);
            }
        }
    public:
        bool GetPaths(std::vector<config::CPath> &m_Paths)
        {
            auto element = this->FirstChildElement("Paths");
            if (element != nullptr)
            {
                VALIDATE(this->GetPaths(element, m_Paths));
                return true;
            }
            return false;
        }
        void SetPaths(std::vector<config::CPath> &m_Paths)
        {
            auto element = this->NewElement("Paths");
            this->LinkEndChild(element);
            this->SetPaths(element, m_Paths);
        }
    public:
        bool GetItem(config::CItem &m_Item)
        {
            auto element = this->FirstChildElement("Item");
            if (element != nullptr)
            {
                VALIDATE(this->GetItem(element, m_Item));
                return true;
            }
            return false;
        }
        void SetItem(config::CItem &m_Item)
        {
            auto element = this->NewElement("Item");
            this->LinkEndChild(element);
            this->SetItem(element, m_Item, -1);
        }
        bool GetItems(std::vector<config::CItem> &m_Items)
        {
            auto element = this->FirstChildElement("Items");
            if (element != nullptr)
            {
                VALIDATE(this->GetItems(element, m_Items));
                return true;
            }
            return false;
        }
        void SetItems(std::vector<config::CItem> &m_Items)
        {
            auto element = this->NewElement("Items");
            this->LinkEndChild(element);
            this->SetItems(element, m_Items);
        }
    };

    class XmlLanguages : public XmlDoc
    {
    public:
        XmlLanguages(XmlDocumnent &doc) : XmlDoc(doc) { }
        virtual ~XmlLanguages() { }
    public:
        bool GetLanguage(const XmlElement *parent, config::CLanguage &m_Language)
        {
            VALIDATE(GetAttributeValueString(parent, "id", &m_Language.szId));
            VALIDATE(GetAttributeValueString(parent, "original", &m_Language.szOriginalName));
            VALIDATE(GetAttributeValueString(parent, "translated", &m_Language.szTranslatedName));

            auto element = parent->FirstChildElement("String");
            if (element != nullptr)
            {
                for (element; element; element = element->NextSiblingElement())
                {
                    std::wstring szKey;
                    std::wstring szValue;

                    VALIDATE(GetAttributeValueString(element, "key", &szKey));
                    VALIDATE(GetAttributeValueString(element, "value", &szValue));

                    int nKey = util::string::ToIntFromHex(szKey);
                    m_Language.m_Strings[nKey] = std::move(szValue);
                }
                return true;
            }
            return false;
        }
        void SetLanguage(XmlElement *parent, config::CLanguage &m_Language)
        {
            SetAttributeValueString(parent, "id", m_Language.szId);
            SetAttributeValueString(parent, "original", m_Language.szOriginalName);
            SetAttributeValueString(parent, "translated", m_Language.szTranslatedName);

            for (auto& item : m_Language.m_Strings)
            {
                int nKey = item.first;
                std::wstring szKey = util::string::ToWStringHex(nKey);

                auto element = this->NewElement("String");
                parent->LinkEndChild(element);

                SetAttributeValueString(element, "", szKey);
                SetAttributeValueString(element, "", item.second);
            }
        }
    public:
        bool GetLanguage(config::CLanguage &m_Language)
        {
            auto element = this->FirstChildElement("Language");
            if (element != nullptr)
            {
                VALIDATE(this->GetLanguage(element, m_Language));
                return true;
            }
            return false;
        }
        void SetLanguage(config::CLanguage &m_Language)
        {
            auto element = this->NewElement("Language");
            this->LinkEndChild(element);
            this->SetLanguage(element, m_Language);
        }
    };

    class XmlOutputs : public XmlDoc
    {
    public:
        XmlOutputs(XmlDocumnent &doc) : XmlDoc(doc) { }
        virtual ~XmlOutputs() { }
    public:
        bool GetOutputs(const XmlElement *parent, std::vector<std::wstring> &outputs)
        {
            auto element = parent->FirstChildElement("Output");
            if (element != nullptr)
            {
                for (element; element; element = element->NextSiblingElement())
                {
                    std::wstring pattern;
                    VALIDATE(GetAttributeValueString(element, "pattern", &pattern));
                    outputs.emplace_back(std::move(pattern));
                }
                return true;
            }
            return false;
        }
        void SetOutputs(XmlElement *parent, std::vector<std::wstring> &outputs)
        {
            for (auto& output : outputs)
            {
                auto element = this->NewElement("Output");
                parent->LinkEndChild(element);
                SetAttributeValueString(element, "pattern", output);
            }
        }
    public:
        bool GetOutputs(std::vector<std::wstring> &outputs)
        {
            auto element = this->FirstChildElement("Outputs");
            if (element != nullptr)
            {
                VALIDATE(this->GetOutputs(element, outputs));
                return true;
            }
            return false;
        }
        void SetOutputs(std::vector<std::wstring> &outputs)
        {
            auto element = this->NewElement("Outputs");
            this->LinkEndChild(element);
            this->SetOutputs(element, outputs);
        }
    };

    class XmlPresets : public XmlDoc
    {
    public:
        XmlPresets(XmlDocumnent &doc) : XmlDoc(doc) { }
        virtual ~XmlPresets() { }
    public:
        bool GetPreset(const XmlElement *element, config::CPreset &m_Preset)
        {
            VALIDATE(GetAttributeValueString(element, "name", &m_Preset.szName));
            VALIDATE(GetAttributeValueString(element, "options", &m_Preset.szOptions));
            return true;
        }
        void SetPreset(XmlElement *element, config::CPreset &m_Preset)
        {
            SetAttributeValueString(element, "name", m_Preset.szName);
            SetAttributeValueString(element, "options", m_Preset.szOptions);
        }
        bool GetPresets(const XmlElement *parent, std::vector<config::CPreset> &m_Presets)
        {
            auto element = parent->FirstChildElement("Preset");
            if (element != nullptr)
            {
                for (element; element; element = element->NextSiblingElement())
                {
                    config::CPreset preset;
                    VALIDATE(this->GetPreset(element, preset));
                    m_Presets.emplace_back(std::move(preset));
                }
                return true;
            }
            return false;
        }
        void SetPresets(XmlElement *parent, std::vector<config::CPreset> &m_Presets)
        {
            size_t nPresets = m_Presets.size();
            for (size_t i = 0; i < nPresets; i++)
            {
                config::CPreset& preset = m_Presets[i];
                auto element = this->NewElement("Preset");
                this->SetPreset(element, preset);
                parent->LinkEndChild(element);
            }
        }
    public:
        bool GetPreset(config::CPreset &m_Preset)
        {
            auto element = this->FirstChildElement("Preset");
            if (element != nullptr)
            {
                VALIDATE(this->GetPreset(element, m_Preset));
                return true;
            }
            return false;
        }
        void SetPreset(config::CPreset &m_Preset)
        {
            auto element = this->NewElement("Preset");
            this->LinkEndChild(element);
            this->SetPreset(element, m_Preset);
        }
        bool GetPresets(std::vector<config::CPreset> &m_Presets)
        {
            auto element = this->FirstChildElement("Presets");
            if (element != nullptr)
            {
                VALIDATE(this->GetPresets(element, m_Presets));
                return true;
            }
            return false;
        }
        void SetPresets(std::vector<config::CPreset> &m_Presets)
        {
            auto element = this->NewElement("Presets");
            this->LinkEndChild(element);
            this->SetPresets(element, m_Presets);
        }
    };

    class XmlFormats : public XmlDoc
    {
    public:
        XmlFormats(XmlDocumnent &doc) : XmlDoc(doc) { }
        virtual ~XmlFormats() { }
    public:
        bool GetFormat(const XmlElement *element, config::CFormat &m_Format)
        {
            VALIDATE(GetAttributeValueString(element, "id", &m_Format.szId));
            VALIDATE(GetAttributeValueString(element, "name", &m_Format.szName));
            VALIDATE(GetAttributeValueString(element, "template", &m_Format.szTemplate));
            VALIDATE(GetAttributeValueBool(element, "input", &m_Format.bPipeInput));
            VALIDATE(GetAttributeValueBool(element, "output", &m_Format.bPipeOutput));
            VALIDATE(GetAttributeValueString(element, "function", &m_Format.szFunction));
            VALIDATE(GetAttributeValueString(element, "path", &m_Format.szPath));
            VALIDATE(GetAttributeValueInt(element, "success", &m_Format.nExitCodeSuccess));

            int nType;
            VALIDATE(GetAttributeValueInt(element, "type", &nType));
            m_Format.nType = config::CFormat::FromInt(nType);

            VALIDATE(GetAttributeValueInt(element, "priority", &m_Format.nPriority));

            VALIDATE(GetAttributeValueString(element, "formats", &m_Format.szInputExtensions));
            VALIDATE(GetAttributeValueString(element, "extension", &m_Format.szOutputExtension));
            VALIDATE(GetAttributeValueSizeT(element, "default", &m_Format.nDefaultPreset));

            auto parent = element->FirstChildElement("Presets");
            if (parent != nullptr)
            {
                VALIDATE(XmlPresets(m_Document).GetPresets(parent, m_Format.m_Presets));
                return true;
            }
            return false;
        }
        void SetFormat(XmlElement *element, config::CFormat &m_Format)
        {
            SetAttributeValueString(element, "id", m_Format.szId);
            SetAttributeValueString(element, "name", m_Format.szName);
            SetAttributeValueString(element, "template", m_Format.szTemplate);
            SetAttributeValueBool(element, "input", m_Format.bPipeInput);
            SetAttributeValueBool(element, "output", m_Format.bPipeOutput);
            SetAttributeValueString(element, "function", m_Format.szFunction);
            SetAttributeValueString(element, "path", m_Format.szPath);
            SetAttributeValueInt(element, "success", m_Format.nExitCodeSuccess);

            int nType = config::CFormat::ToInt(m_Format.nType);
            SetAttributeValueInt(element, "type", nType);

            SetAttributeValueInt(element, "priority", m_Format.nPriority);

            SetAttributeValueString(element, "formats", m_Format.szInputExtensions);
            SetAttributeValueString(element, "extension", m_Format.szOutputExtension);
            SetAttributeValueSizeT(element, "default", m_Format.nDefaultPreset);

            auto parent = this->NewElement("Presets");
            element->LinkEndChild(parent);
            XmlPresets(m_Document).SetPresets(parent, m_Format.m_Presets);
        }
    public:
        bool GetFormat(config::CFormat &m_Format)
        {
            auto element = this->FirstChildElement("Format");
            if (element != nullptr)
            {
                VALIDATE(this->GetFormat(element, m_Format));
                return true;
            }
            return false;
        }
        void SetFormat(config::CFormat &m_Format)
        {
            auto element = this->NewElement("Format");
            this->LinkEndChild(element);
            this->SetFormat(element, m_Format);
        }
    };

    class XmlTools : public XmlDoc
    {
    public:
        XmlTools(XmlDocumnent &doc) : XmlDoc(doc) { }
        virtual ~XmlTools() { }
    public:
        bool GetTool(const XmlElement *element, config::CTool &m_Tool)
        {
            VALIDATE(GetAttributeValueString(element, "name", &m_Tool.szName));
            VALIDATE(GetAttributeValueString(element, "platform", &m_Tool.szPlatform));
            VALIDATE(GetAttributeValueInt(element, "priority", &m_Tool.nPriority));
            VALIDATE(GetAttributeValueString(element, "formats", &m_Tool.szFormats));
            VALIDATE(GetAttributeValueString(element, "url", &m_Tool.szUrl));
            VALIDATE(GetAttributeValueString(element, "file", &m_Tool.szFile));
            VALIDATE(GetAttributeValueString(element, "extract", &m_Tool.szExtract));
            VALIDATE(GetAttributeValueString(element, "path", &m_Tool.szPath));
            return true;
        }
        void SetTool(XmlElement *element, config::CTool &m_Tool)
        {
            SetAttributeValueString(element, "name", m_Tool.szName);
            SetAttributeValueString(element, "platform", m_Tool.szPlatform);
            SetAttributeValueInt(element, "priority", m_Tool.nPriority);
            SetAttributeValueString(element, "formats", m_Tool.szFormats);
            SetAttributeValueString(element, "url", m_Tool.szUrl);
            SetAttributeValueString(element, "file", m_Tool.szFile);
            SetAttributeValueString(element, "extract", m_Tool.szExtract);
            SetAttributeValueString(element, "path", m_Tool.szPath);
        }
    public:
        bool GetTool(config::CTool &m_Tool)
        {
            auto element = this->FirstChildElement("Tool");
            if (element != nullptr)
            {
                VALIDATE(this->GetTool(element, m_Tool));
                return true;
            }
            return false;
        }
        void SetTool(config::CTool &m_Tool)
        {
            auto element = this->NewElement("Tool");
            this->LinkEndChild(element);
            this->SetTool(element, m_Tool);
        }
    };

    class XmlConfig
    {
    public:
        static std::string GetRootName(const std::wstring& szFileXml, XmlDocumnent &doc)
        {
            if (XmlDoc::Open(szFileXml, doc) == true)
            {
                const char *name = XmlDoc::GetRootName(doc);
                if (name != nullptr)
                    return std::string(name);
            }
            return std::string();
        }
    public:
        static bool LoadOptions(XmlDocumnent &doc, config::COptions &options)
        {
            XmlOptions xml(doc);
            return xml.GetOptions(options);
        }
        static bool LoadOptions(const std::wstring& szFileXml, config::COptions &options)
        {
            XmlDocumnent doc;
            if (XmlDoc::Open(szFileXml, doc) == true)
                return LoadOptions(doc, options);
            return false;
        }
        static bool SaveOptions(const std::wstring& szFileXml, config::COptions &options)
        {
            XmlDocumnent doc;
            XmlOptions xml(doc);
            xml.Create();
            xml.SetOptions(options);
            return xml.Save(szFileXml);
        }
    public:
        static bool LoadPaths(XmlDocumnent &doc, std::vector<config::CPath> &paths)
        {
            XmlItems xml(doc);
            return xml.GetPaths(paths);
        }
        static bool LoadPaths(const std::wstring& szFileXml, std::vector<config::CPath> &paths)
        {
            XmlDocumnent doc;
            if (XmlDoc::Open(szFileXml, doc) == true)
                return LoadPaths(doc, paths);
            return false;
        }
        static bool SavePaths(const std::wstring& szFileXml, std::vector<config::CPath> &paths)
        {
            XmlDocumnent doc;
            XmlItems xml(doc);
            xml.Create();
            xml.SetPaths(paths);
            return xml.Save(szFileXml);
        }
    public:
        static bool LoadItem(XmlDocumnent &doc, config::CItem &item)
        {
            XmlItems xml(doc);
            return xml.GetItem(item);
        }
        static bool LoadItem(const std::wstring& szFileXml, config::CItem &item)
        {
            XmlDocumnent doc;
            if (XmlDoc::Open(szFileXml, doc) == true)
                return LoadItem(doc, item);
            return false;
        }
        static bool SaveItem(const std::wstring& szFileXml, config::CItem &item)
        {
            XmlDocumnent doc;
            XmlItems xml(doc);
            xml.Create();
            xml.SetItem(item);
            return xml.Save(szFileXml);
        }
        static bool LoadItems(XmlDocumnent &doc, std::vector<config::CItem> &items)
        {
            XmlItems xml(doc);
            return xml.GetItems(items);
        }
        static bool LoadItems(const std::wstring& szFileXml, std::vector<config::CItem> &items)
        {
            XmlDocumnent doc;
            if (XmlDoc::Open(szFileXml, doc) == true)
                return LoadItems(doc, items);
            return false;
        }
        static bool SaveItems(const std::wstring& szFileXml, std::vector<config::CItem> &items)
        {
            XmlDocumnent doc;
            XmlItems xml(doc);
            xml.Create();
            xml.SetItems(items);
            return xml.Save(szFileXml);
        }
    public:
        static bool LoadLanguage(XmlDocumnent &doc, config::CLanguage &language)
        {
            XmlLanguages xml(doc);
            return xml.GetLanguage(language);
        }
        static bool LoadLanguage(const std::wstring& szFileXml, config::CLanguage &language)
        {
            XmlDocumnent doc;
            if (XmlDoc::Open(szFileXml, doc) == true)
                return LoadLanguage(doc, language);
            return false;
        }
        static bool SaveLanguage(const std::wstring& szFileXml, config::CLanguage &language)
        {
            XmlDocumnent doc;
            XmlLanguages xml(doc);
            xml.Create();
            xml.SetLanguage(language);
            return xml.Save(szFileXml);
        }
    public:
        static bool LoadOutputs(XmlDocumnent &doc, std::vector<std::wstring> &outputs)
        {
            XmlOutputs xml(doc);
            return xml.GetOutputs(outputs);
        }
        static bool LoadOutputs(const std::wstring& szFileXml, std::vector<std::wstring> &outputs)
        {
            XmlDocumnent doc;
            if (XmlDoc::Open(szFileXml, doc) == true)
                return LoadOutputs(doc, outputs);
            return false;
        }
        static bool SaveOutputs(const std::wstring& szFileXml, std::vector<std::wstring> &outputs)
        {
            XmlDocumnent doc;
            XmlOutputs xml(doc);
            xml.Create();
            xml.SetOutputs(outputs);
            return xml.Save(szFileXml);
        }
    public:
        static bool LoadPreset(XmlDocumnent &doc, config::CPreset &preset)
        {
            XmlPresets xml(doc);
            return xml.GetPreset(preset);
        }
        static bool LoadPreset(const std::wstring& szFileXml, config::CPreset &preset)
        {
            XmlDocumnent doc;
            if (XmlDoc::Open(szFileXml, doc) == true)
                return LoadPreset(doc, preset);
            return false;
        }
        static bool SavePreset(const std::wstring& szFileXml, config::CPreset &preset)
        {
            XmlDocumnent doc;
            XmlPresets xml(doc);
            xml.Create();
            xml.SetPreset(preset);
            return xml.Save(szFileXml);
        }
        static bool LoadPresets(XmlDocumnent &doc, std::vector<config::CPreset> &presets)
        {
            XmlPresets xml(doc);
            return xml.GetPresets(presets);
        }
        static bool LoadPresets(const std::wstring& szFileXml, std::vector<config::CPreset> &presets)
        {
            XmlDocumnent doc;
            if (XmlDoc::Open(szFileXml, doc) == true)
                return LoadPresets(doc, presets);
            return false;
        }
        static bool SavePresets(const std::wstring& szFileXml, std::vector<config::CPreset> &presets)
        {
            XmlDocumnent doc;
            XmlPresets xml(doc);
            xml.Create();
            xml.SetPresets(presets);
            return xml.Save(szFileXml);
        }
    public:
        static bool LoadFormat(XmlDocumnent &doc, config::CFormat &format)
        {
            XmlFormats xml(doc);
            return xml.GetFormat(format);
        }
        static bool LoadFormat(const std::wstring& szFileXml, config::CFormat &format)
        {
            XmlDocumnent doc;
            if (XmlDoc::Open(szFileXml, doc) == true)
                return LoadFormat(doc, format);
            return false;
        }
        static bool SaveFormat(const std::wstring& szFileXml, config::CFormat &format)
        {
            XmlDocumnent doc;
            XmlFormats xml(doc);
            xml.Create();
            xml.SetFormat(format);
            return xml.Save(szFileXml);
        }
    public:
        static bool LoadTool(XmlDocumnent &doc, config::CTool &tool)
        {
            XmlTools xml(doc);
            return xml.GetTool(tool);
        }
        static bool LoadTool(const std::wstring& szFileXml, config::CTool &tool)
        {
            XmlDocumnent doc;
            if (XmlDoc::Open(szFileXml, doc) == true)
                return LoadTool(doc, tool);
            return false;
        }
        static bool SaveTool(const std::wstring& szFileXml, config::CTool &tool)
        {
            XmlDocumnent doc;
            XmlTools xml(doc);
            xml.Create();
            xml.SetTool(tool);
            return xml.Save(szFileXml);
        }
    };
}

namespace config
{
    class CConfig
    {
    public:
        std::unique_ptr<util::IFileSystem> FileSystem;
        std::unique_ptr<util::ILog> Log;
        CSettings m_Settings;
        COptions m_Options;
        std::vector<CFormat> m_Formats;
        std::vector<CItem> m_Items;
        std::vector<CTool> m_Tools;
        size_t nLangId;
        std::vector<CLanguage> m_Languages;
        std::vector<std::wstring> m_Outputs;
    public:
        int AddItem(const std::wstring& szPath, int nFormat, int nPreset)
        {
            std::wstring szFormatId = L"";
            int nFormatId = nFormat;
            int nPresetId = nPreset;
            std::wstring szExt = FileSystem->GetFileExtension(szPath);
            std::wstring szName = FileSystem->GetOnlyFileName(szPath);
            unsigned __int64 nFileSize = FileSystem->GetFileSize64(szPath);

            if ((nFormatId >= 0) && (nFormatId < (int)this->m_Formats.size()))
            {
                const auto& format = this->m_Formats[nFormatId];
                szFormatId = format.szId;
            }

            if (this->m_Options.bTryToFindDecoder == true)
            {
                int nDecoder = CFormat::GetDecoderByExtension(this->m_Formats, szExt);
                if ((nDecoder >= 0) && (nDecoder < (int)this->m_Formats.size()))
                {
                    const auto& format = this->m_Formats[nDecoder];
                    szFormatId = format.szId;
                    nPresetId = format.nDefaultPreset;
                }
            }

            CItem item;

            CPath path;
            path.szPath = szPath;
            path.nSize = nFileSize;
            item.m_Paths.emplace_back(std::move(path));

            item.nSize = nFileSize;
            item.szName = std::move(szName);
            item.szExtension = util::string::ToUpper(szExt);
            item.szFormatId = std::move(szFormatId);
            item.nPreset = nPresetId;
            item.bChecked = true;

            this->m_Items.emplace_back(std::move(item));

            return (int)this->m_Items.size() - 1;
        }
        void RemoveItems(std::vector<int>& keep)
        {
            std::vector<CItem> items;

            for (size_t i = 0; i < keep.size(); i++)
            {
                int nIndex = keep[i];
                auto& item = this->m_Items[nIndex];
                items.emplace_back(std::move(item));
            }

            this->m_Items = std::move(items);
        }
    public:
        inline bool LookupString(const int nKey, std::wstring& rValue)
        {
            if (this->nLangId >= 0 && this->nLangId < this->m_Languages.size())
            {
                auto& language = this->m_Languages[this->nLangId];
                if (language.m_Strings.count(nKey) == 1)
                {
                    rValue = language.m_Strings[nKey];
                    return true;
                }
            }
            return false;
        }
        inline std::wstring GetString(int nKey, const std::wstring& szDefault)
        {
            std::wstring rValue;
            if (this->LookupString(nKey, rValue))
                return rValue;
            return szDefault;
        }
        inline std::wstring GetString(int nKey)
        {
            std::wstring rValue;
            if (this->LookupString(nKey, rValue))
                return rValue;

            if (config::m_Strings.count(nKey) == 1)
                return config::m_Strings.at(nKey);

            return L"??";
        }
    public:
        static inline int FindTool(std::vector<config::CTool>& m_Tools, const std::wstring& szPlatform, const std::wstring& szFormatId)
        {
            int nTool = config::CTool::GetToolByFormatAndPlatform(m_Tools, szFormatId, szPlatform);
            if (nTool >= 0)
            {
                return nTool;
            }
            return -1;
        }
        static inline int FindTool(std::vector<config::CTool>& m_Tools, const std::wstring& szFormatId)
        {
            const std::wstring szPlatformX86 = L"x86";
            const std::wstring szPlatformX64 = L"x64";
#if defined(_WIN32) & !defined(_WIN64)
            return FindTool(m_Tools, szPlatformX86, szFormatId);
#else
            int nTool = FindTool(m_Tools, szPlatformX64, szFormatId);
            if (nTool == -1)
                return FindTool(m_Tools, szPlatformX86, szFormatId);
            return nTool;
#endif
        }
        static inline void SetFormatPaths(std::vector<config::CFormat>& m_Formats, std::vector<config::CTool>& m_Tools, const std::wstring& szPlatform)
        {
            size_t nFormats = m_Formats.size();
            for (size_t i = 0; i < nFormats; i++)
            {
                config::CFormat& format = m_Formats[i];
                int nTool = config::CTool::GetToolByFormatAndPlatform(m_Tools, format.szId, szPlatform);
                if (nTool >= 0)
                {
                    config::CTool& tool = m_Tools[nTool];
                    format.szPath = tool.szPath;
                }
            }
        }
        static inline void SetFormatPaths(std::vector<config::CFormat>& m_Formats, std::vector<config::CTool>& m_Tools, std::function<bool(int, config::CTool&)> filter)
        {
            size_t nTools = m_Tools.size();
            size_t nFormats = m_Formats.size();
            if ((nTools > 0) && (nFormats > 0))
            {
                for (size_t i = 0; i < nTools; i++)
                {
                    config::CTool& tool = m_Tools[i];
                    if (filter(i, tool) == true)
                    {
                        for (size_t i = 0; i < nFormats; i++)
                        {
                            config::CFormat& format = m_Formats[i];
                            if (CTool::IsValidFormat(tool.szFormats, format.szId))
                            {
                                format.szPath = tool.szPath;
                            }
                        }
                    }
                }
            }
        }
    public:
        void CleanFiles(const std::wstring& szPath)
        {
            std::vector<std::wstring> files;
            if (FileSystem->FindFiles(szPath, files, false) == true)
            {
                for (auto& file : files)
                {
                    std::wstring szExt = FileSystem->GetFileExtension(file);
                    if (util::string::CompareNoCase(szExt, L"xml"))
                    {
                        FileSystem->DeleteFile_(file);
                    }
                }
            }
        }
    public:
        bool LoadOptions(const std::wstring& szFileXml)
        {
            xml::XmlDocumnent doc;
            std::string szName = xml::XmlConfig::GetRootName(szFileXml, doc);
            if (!szName.empty() && util::string::CompareNoCase(szName, "Options"))
            {
                return this->LoadOptions(doc);
            }
            return false;
        }
        bool LoadOptions(xml::XmlDocumnent &doc)
        {
            config::COptions options;
            if (xml::XmlConfig::LoadOptions(doc, options))
            {
                this->m_Options = std::move(options);
                return true;
            }
            return false;
        }
        bool SaveOptions(const std::wstring& szFileXml)
        {
            return xml::XmlConfig::SaveOptions(szFileXml, this->m_Options);
        }
        bool LoadFormats(const std::wstring& szPath)
        {
            std::vector<std::wstring> files;
            bool bResult = FileSystem->FindFiles(szPath, files, false);
            if (bResult == true)
            {
                std::vector<config::CFormat> formats;
                for (auto& file : files)
                {
                    xml::XmlDocumnent doc;
                    if (xml::XmlDoc::Open(file, doc) == true)
                    {
                        std::string szName = xml::XmlDoc::GetRootName(doc);
                        if (util::string::CompareNoCase(szName, "Format"))
                        {
                            config::CFormat format;
                            if (xml::XmlConfig::LoadFormat(doc, format))
                            {
                                formats.emplace_back(std::move(format));
                            }
                        }
                    }
                }

                config::CFormat::Sort(formats);
                this->m_Formats = std::move(formats);

                return true;
            }
            return false;
        }
        bool SaveFormats(const std::wstring& szPath)
        {
            FileSystem->CreateDirectory_(szPath);
            this->CleanFiles(szPath);
            for (auto& format : this->m_Formats)
            {
                std::wstring path = FileSystem->CombinePath(szPath, format.szId + L".xml");
                if (this->SaveFormat(path, format) == false)
                    return false;
            }

            return true;
        }
        bool LoadFormat(const std::wstring& szFileXml)
        {
            xml::XmlDocumnent doc;
            std::string szName = xml::XmlConfig::GetRootName(szFileXml, doc);
            if (!szName.empty() && util::string::CompareNoCase(szName, "Format"))
            {
                return this->LoadFormat(doc);
            }
            return false;
        }
        bool LoadFormat(xml::XmlDocumnent &doc)
        {
            config::CFormat format;
            if (xml::XmlConfig::LoadFormat(doc, format))
            {
                this->m_Formats.emplace_back(std::move(format));
                config::CFormat::Sort(this->m_Formats);
                return true;
            }
            return false;
        }
        bool SaveFormat(const std::wstring& szFileXml, config::CFormat& format)
        {
            return xml::XmlConfig::SaveFormat(szFileXml, format);
        }
        bool LoadPresets(const std::wstring& szFileXml, const int nFormat)
        {
            xml::XmlDocumnent doc;
            std::string szName = xml::XmlConfig::GetRootName(szFileXml, doc);
            if (!szName.empty() && util::string::CompareNoCase(szName, "Presets"))
            {
                return this->LoadPresets(doc, nFormat);
            }
            return false;
        }
        bool LoadPresets(xml::XmlDocumnent &doc, const int nFormat)
        {
            std::vector<config::CPreset> presets;
            if (xml::XmlConfig::LoadPresets(doc, presets))
            {
                config::CFormat& format = this->m_Formats[nFormat];
                format.m_Presets = std::move(presets);
                return true;
            }
            return false;
        }
        bool SavePresets(const std::wstring& szFileXml, const int nFormat)
        {
            config::CFormat& format = this->m_Formats[nFormat];
            return xml::XmlConfig::SavePresets(szFileXml, format.m_Presets);
        }
        bool LoadTools(const std::wstring& szPath)
        {
            std::vector<std::wstring> files;
            bool bResult = FileSystem->FindFiles(szPath, files, false);
            if (bResult == true)
            {
                std::vector<config::CTool> tools;
                for (auto& file : files)
                {
                    xml::XmlDocumnent doc;
                    if (xml::XmlDoc::Open(file, doc) == true)
                    {
                        std::string szName = xml::XmlDoc::GetRootName(doc);
                        if (util::string::CompareNoCase(szName, "Tool"))
                        {
                            config::CTool tool;
                            if (xml::XmlConfig::LoadTool(doc, tool))
                            {
                                tools.emplace_back(std::move(tool));
                            }
                        }
                    }
                }

                config::CTool::Sort(tools);
                this->m_Tools = std::move(tools);

                return true;
            }
            return false;
        }
        bool SaveTools(const std::wstring& szPath)
        {
            FileSystem->CreateDirectory_(szPath);
            this->CleanFiles(szPath);
            for (auto& tool : this->m_Tools)
            {
                std::wstring path = FileSystem->CombinePath(szPath, tool.szName + L".xml");
                if (this->SaveTool(path, tool) == false)
                    return false;
            }

            return true;
        }
        bool LoadTool(const std::wstring& szFileXml)
        {
            xml::XmlDocumnent doc;
            std::string szName = xml::XmlConfig::GetRootName(szFileXml, doc);
            if (!szName.empty() && util::string::CompareNoCase(szName, "Tool"))
            {
                return this->LoadTool(doc);
            }
            return false;
        }
        bool LoadTool(xml::XmlDocumnent &doc)
        {
            config::CTool tool;
            if (xml::XmlConfig::LoadTool(doc, tool))
            {
                this->m_Tools.emplace_back(std::move(tool));
                config::CTool::Sort(this->m_Tools);
                return true;
            }
            return false;
        }
        bool SaveTool(const std::wstring& szFileXml, config::CTool& tool)
        {
            return xml::XmlConfig::SaveTool(szFileXml, tool);
        }
        bool LoadItems(const std::wstring& szFileXml)
        {
            xml::XmlDocumnent doc;
            std::string szName = xml::XmlConfig::GetRootName(szFileXml, doc);
            if (!szName.empty() && util::string::CompareNoCase(szName, "Items"))
            {
                return this->LoadItems(doc);
            }
            return false;
        }
        bool LoadItems(xml::XmlDocumnent &doc)
        {
            std::vector<config::CItem> items;
            if (xml::XmlConfig::LoadItems(doc, items))
            {
                this->m_Items = std::move(items);
                return true;
            }
            return false;
        }
        bool SaveItems(const std::wstring& szFileXml)
        {
            return xml::XmlConfig::SaveItems(szFileXml, this->m_Items);
        }
        bool LoadOutputs(const std::wstring& szFileXml)
        {
            xml::XmlDocumnent doc;
            std::string szName = xml::XmlConfig::GetRootName(szFileXml, doc);
            if (!szName.empty() && util::string::CompareNoCase(szName, "Outputs"))
            {
                return this->LoadOutputs(doc);
            }
            return false;
        }
        bool LoadOutputs(xml::XmlDocumnent &doc)
        {
            std::vector<std::wstring> outputs;
            if (xml::XmlConfig::LoadOutputs(doc, outputs))
            {
                this->m_Outputs = std::move(outputs);
                return true;
            }
            return false;
        }
        bool SaveOutputs(const std::wstring& szFileXml)
        {
            return xml::XmlConfig::SaveOutputs(szFileXml, this->m_Outputs);
        }
        bool LoadLanguages(const std::wstring& szPath)
        {
            std::vector<std::wstring> files;
            bool bResult = FileSystem->FindFiles(szPath, files, false);
            if (bResult == true)
            {
                std::vector<config::CLanguage> languages;
                for (auto& file : files)
                {
                    xml::XmlDocumnent doc;
                    if (xml::XmlDoc::Open(file, doc) == true)
                    {
                        std::string szName = xml::XmlDoc::GetRootName(doc);
                        if (util::string::CompareNoCase(szName, "Language"))
                        {
                            config::CLanguage language;
                            if (xml::XmlConfig::LoadLanguage(doc, language))
                            {
                                languages.emplace_back(std::move(language));
                            }
                        }
                    }
                }

                this->m_Languages = std::move(languages);

                return true;
            }
            return false;
        }
        bool LoadLanguage(const std::wstring& szFileXml)
        {
            xml::XmlDocumnent doc;
            std::string szName = xml::XmlConfig::GetRootName(szFileXml, doc);
            if (!szName.empty() && util::string::CompareNoCase(szName, "Language"))
            {
                return this->LoadLanguage(doc);
            }
            return false;
        }
        bool LoadLanguage(xml::XmlDocumnent &doc)
        {
            config::CLanguage language;
            if (xml::XmlConfig::LoadLanguage(doc, language))
            {
                this->m_Languages.emplace_back(std::move(language));
                return true;
            }
            return false;
        }
    };
}


text:
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/policy/reporting/metrics_reporting/apps/app_events_observer.h"

#include <memory>
#include <tuple>

#include "base/memory/raw_ptr.h"
#include "chrome/browser/apps/app_service/app_launch_params.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/app_service/launch_result_type.h"
#include "chrome/browser/apps/app_service/metrics/app_platform_metrics.h"
#include "chrome/browser/apps/app_service/metrics/app_platform_metrics_service_test_base.h"
#include "chrome/browser/apps/app_service/publishers/app_publisher.h"
#include "components/reporting/proto/synced/metric_data.pb.h"
#include "components/reporting/util/test_support_callbacks.h"
#include "components/services/app_service/public/cpp/app_launch_util.h"
#include "components/services/app_service/public/cpp/app_types.h"
#include "components/services/app_service/public/cpp/icon_types.h"
#include "components/services/app_service/public/protos/app_types.pb.h"
#include "testing/gtest/include/gtest/gtest.h"

using ::testing::Eq;
using ::testing::StrEq;

namespace reporting {
namespace {

constexpr char kTestAppId[] = "TestApp";

// Test delegate that stubs out `AppEventsObserver` interactions with the
// `AppServiceProxyFactory`.
class TestDelegate : public AppEventsObserver::Delegate {
 public:
  TestDelegate(bool is_app_service_available,
               ::apps::AppPlatformMetrics* app_platform_metrics)
      : is_app_service_available_(is_app_service_available),
        app_platform_metrics_(app_platform_metrics) {}
  TestDelegate(const TestDelegate& other) = delete;
  TestDelegate& operator=(const TestDelegate& other) = delete;
  ~TestDelegate() override = default;

  // AppEventsObserver::Delegate:
  bool IsAppServiceAvailableForProfile(Profile* profile) override {
    return is_app_service_available_;
  }

  // AppEventsObserver::Delegate:
  ::apps::AppPlatformMetrics* GetAppPlatformMetricsForProfile(
      Profile* profile) override {
    return app_platform_metrics_.get();
  }

 private:
  const bool is_app_service_available_;
  const raw_ptr<::apps::AppPlatformMetrics> app_platform_metrics_;
};

// Fake `AppPublisher` used by the test to simulate app launches.
class FakePublisher : public ::apps::AppPublisher {
 public:
  FakePublisher(::apps::AppServiceProxy* proxy, ::apps::AppType app_type)
      : ::apps::AppPublisher(proxy) {
    RegisterPublisher(app_type);
  }

  MOCK_METHOD(void,
              Launch,
              (const std::string& app_id,
               int32_t event_flags,
               ::apps::LaunchSource launch_source,
               ::apps::WindowInfoPtr window_info));

  MOCK_METHOD(void,
              LaunchAppWithParams,
              (::apps::AppLaunchParams && params,
               ::apps::LaunchCallback callback));

  MOCK_METHOD(void,
              LoadIcon,
              (const std::string& app_id,
               const ::apps::IconKey& icon_key,
               ::apps::IconType icon_type,
               int32_t size_hint_in_dip,
               bool allow_placeholder_icon,
               ::apps::LoadIconCallback callback));
};

class AppEventsObserverTest
    : public ::apps::AppPlatformMetricsServiceTestBase,
      public ::testing::WithParamInterface<std::tuple<bool, bool>> {
 protected:
  void SetUp() override {
    ::apps::AppPlatformMetricsServiceTestBase::SetUp();

    // Pre-install app so it can be used by tests.
    InstallOneApp(kTestAppId, ::apps::AppType::kArc, /*publisher_id=*/"",
                  ::apps::Readiness::kReady, ::apps::InstallSource::kPlayStore);

    // Set up `AppEventsObserver` with relevant test params.
    auto delegate = std::make_unique<TestDelegate>(
        IsAppServiceAvailableForProfile(),
        app_platform_metrics_service()->AppPlatformMetrics());
    app_events_observer_ =
        AppEventsObserver::CreateForTest(profile(), std::move(delegate));
    app_events_observer_->SetReportingEnabled(IsReportingEnabled());
  }

  void TearDown() override {
    app_events_observer_.reset();
    ::apps::AppPlatformMetricsServiceTestBase::TearDown();
  }

  bool IsAppServiceAvailableForProfile() const {
    return ::testing::get<0>(GetParam());
  }

  bool IsReportingEnabled() const { return ::testing::get<1>(GetParam()); }

  std::unique_ptr<AppEventsObserver> app_events_observer_;
};

TEST_P(AppEventsObserverTest, OnAppInstalled) {
  test::TestEvent<MetricData> test_event;
  app_events_observer_->SetOnEventObservedCallback(test_event.repeating_cb());

  // Install new app.
  static constexpr char app_id[] = "TestNewApp";
  InstallOneApp(app_id, ::apps::AppType::kStandaloneBrowser,
                /*publisher_id=*/"", ::apps::Readiness::kReady,
                ::apps::InstallSource::kBrowser);

  if (IsAppServiceAvailableForProfile() && IsReportingEnabled()) {
    // Verify data being reported.
    const MetricData& result = test_event.result();
    ASSERT_TRUE(result.has_event_data());
    EXPECT_THAT(result.event_data().type(), Eq(MetricEventType::APP_INSTALLED));
    ASSERT_TRUE(result.has_telemetry_data());
    ASSERT_TRUE(result.telemetry_data().has_app_telemetry());

    const AppTelemetry& app_telemetry_data =
        result.telemetry_data().app_telemetry();
    EXPECT_THAT(app_telemetry_data.app_id(), StrEq(app_id));
    EXPECT_THAT(
        app_telemetry_data.app_type(),
        Eq(::apps::ApplicationType::APPLICATION_TYPE_STANDALONE_BROWSER));
    ASSERT_TRUE(app_telemetry_data.has_app_install_data());

    const AppInstallData& app_install_data =
        result.telemetry_data().app_telemetry().app_install_data();
    EXPECT_THAT(
        app_install_data.app_install_reason(),
        Eq(::apps::ApplicationInstallReason::APPLICATION_INSTALL_REASON_USER));
    EXPECT_THAT(app_install_data.app_install_source(),
                Eq(::apps::ApplicationInstallSource::
                       APPLICATION_INSTALL_SOURCE_BROWSER));
    EXPECT_THAT(
        app_install_data.app_install_time(),
        Eq(::apps::ApplicationInstallTime::APPLICATION_INSTALL_TIME_INIT));
  } else {
    // Should not report any data if app service unavailable or reporting is
    // disabled for profile.
    ASSERT_TRUE(test_event.no_result());
  }
}

TEST_P(AppEventsObserverTest, OnAppLaunched) {
  test::TestEvent<MetricData> test_event;
  app_events_observer_->SetOnEventObservedCallback(test_event.repeating_cb());

  // Simulate app launch for pre-installed app.
  auto* const proxy = ::apps::AppServiceProxyFactory::GetForProfile(profile());
  proxy->SetAppPlatformMetricsServiceForTesting(GetAppPlatformMetricsService());
  FakePublisher fake_publisher(proxy, ::apps::AppType::kArc);
  proxy->Launch(kTestAppId, ui::EF_NONE, apps::LaunchSource::kFromCommandLine,
                nullptr);

  if (IsAppServiceAvailableForProfile() && IsReportingEnabled()) {
    // Verify data being reported.
    const MetricData& result = test_event.result();
    ASSERT_TRUE(result.has_event_data());
    EXPECT_THAT(result.event_data().type(), Eq(MetricEventType::APP_LAUNCHED));
    ASSERT_TRUE(result.has_telemetry_data());
    ASSERT_TRUE(result.telemetry_data().has_app_telemetry());

    const AppTelemetry& app_telemetry_data =
        result.telemetry_data().app_telemetry();
    EXPECT_THAT(app_telemetry_data.app_id(), StrEq(kTestAppId));
    EXPECT_THAT(app_telemetry_data.app_type(),
                Eq(::apps::ApplicationType::APPLICATION_TYPE_ARC));
    ASSERT_TRUE(app_telemetry_data.has_app_launch_data());

    const AppLaunchData& app_launch_data =
        result.telemetry_data().app_telemetry().app_launch_data();
    EXPECT_THAT(app_launch_data.app_launch_source(),
                Eq(::apps::ApplicationLaunchSource::
                       APPLICATION_LAUNCH_SOURCE_COMMAND_LINE));
  } else {
    // Should not report any data if app service unavailable or reporting is
    // disabled for profile.
    ASSERT_TRUE(test_event.no_result());
  }
}

TEST_P(AppEventsObserverTest, OnAppUninstalled) {
  test::TestEvent<MetricData> test_event;
  app_events_observer_->SetOnEventObservedCallback(test_event.repeating_cb());

  // Simulate app uninstall for pre-installed app.
  auto* const proxy = ::apps::AppServiceProxyFactory::GetForProfile(profile());
  proxy->SetAppPlatformMetricsServiceForTesting(GetAppPlatformMetricsService());
  FakePublisher fake_publisher(proxy, ::apps::AppType::kArc);
  proxy->UninstallSilently(kTestAppId, ::apps::UninstallSource::kAppList);

  if (IsAppServiceAvailableForProfile() && IsReportingEnabled()) {
    // Verify data being reported.
    const MetricData& result = test_event.result();
    ASSERT_TRUE(result.has_event_data());
    EXPECT_THAT(result.event_data().type(),
                Eq(MetricEventType::APP_UNINSTALLED));
    ASSERT_TRUE(result.has_telemetry_data());
    ASSERT_TRUE(result.telemetry_data().has_app_telemetry());

    const AppTelemetry& app_telemetry_data =
        result.telemetry_data().app_telemetry();
    EXPECT_THAT(app_telemetry_data.app_id(), StrEq(kTestAppId));
    EXPECT_THAT(app_telemetry_data.app_type(),
                Eq(::apps::ApplicationType::APPLICATION_TYPE_ARC));
    ASSERT_TRUE(app_telemetry_data.has_app_uninstall_data());

    const AppUninstallData& app_uninstall_data =
        result.telemetry_data().app_telemetry().app_uninstall_data();
    EXPECT_THAT(app_uninstall_data.app_uninstall_source(),
                Eq(::apps::ApplicationUninstallSource::
                       APPLICATION_UNINSTALL_SOURCE_APP_LIST));
  } else {
    // Should not report any data if app service unavailable or reporting is
    // disabled for profile.
    ASSERT_TRUE(test_event.no_result());
  }
}

INSTANTIATE_TEST_SUITE_P(
    AppEventsObserverTests,
    AppEventsObserverTest,
    ::testing::Combine(
        ::testing::Bool() /* true - app service available for profile*/,
        ::testing::Bool()) /* true - reporting enabled*/);

}  // namespace
}  // namespace reporting

redpajama_set_name: RedPajamaGithub


text:
from PyQt4.QtGui import *
from subprocess import Popen, PIPE
from Core.Settings import frm_Settings
from os import popen,getpid
from re import search
import threading
import getpass
from time import sleep

global sudo_prompt
sudo_prompt = None
class waiter(threading.Thread):
    def run(self):
        for i in range(2):
            sleep(5)
        if sudo_prompt == None:
            #popen("kill -9 %i"%(getpid()))
            pass

class frm_privelege(QDialog):
    def __init__(self, parent = None):
        super(frm_privelege, self).__init__(parent)
        self.setWindowTitle("Privilege Authentication")
        self.Main = QVBoxLayout()
        self.frm = QFormLayout()
        self.setGeometry(0, 0, 270, 100)
        self.center()
        self.config = frm_Settings()
        self.loadtheme(self.config.XmlThemeSelected())
        self.Qui()

    def loadtheme(self,theme):
        if theme != "theme2":
            sshFile=("Core/%s.css"%(theme))
            with open(sshFile,"r") as fh:
                self.setStyleSheet(fh.read())
        else:
            sshFile=("Core/%s.css"%(theme))
            with open(sshFile,"r") as fh:
                self.setStyleSheet(fh.read())

    def center(self):
        frameGm = self.frameGeometry()
        centerPoint = QDesktopWidget().availableGeometry().center()
        frameGm.moveCenter(centerPoint)
        self.move(frameGm.topLeft())

    def Qui(self):
        self.user = QComboBox()
        self.user.addItem(getpass.getuser())
        self.btn_cancel = QPushButton("Cancel")
        self.btn_ok = QPushButton("Ok")
        self.Editpassword = QLineEdit(self)
        self.Editpassword.setFocus()
        #temporary

        self.Editpassword.setEchoMode(QLineEdit.Password)
        self.btn_cancel.clicked.connect(self.close)
        self.btn_ok.clicked.connect(self.function_ok)
        self.btn_ok.setDefault(True)
        self.frm.addRow("User:", self.user)
        self.frm.addRow("Password:", self.Editpassword)
        self.grid = QGridLayout()
        self.grid.addWidget(self.btn_cancel, 1,2)
        self.grid.addWidget(self.btn_ok, 1,3)
        self.Main.addLayout(self.frm)
        self.Main.addLayout(self.grid)
        self.setLayout(self.Main)

    def function_ok(self):
        out = self.password_check(self.Editpassword.text())
        if search("1 incorrect password attemp",out):
            QMessageBox.information(self, "Sudo Password check", "[sudo] password for %s: Sorry, try again."%(getpass.getuser()))
            self.show()
            self.Editpassword.clear()
        else:
            self.close()

    def password_check(self,sudo_password):
        self.hide()
        self.th = threading.Thread(target=self.thread, args=(sudo_password,))
        self.th.daemon = True
        self.th.start()
        waiter().start()
        self.th.join()
        return sudo_prompt

    def thread(self,sudo_password):
        popen("sudo -k")
        sudo_password = self.Editpassword.text()
        command = 'python functions.py'.split()
        p = Popen(['sudo', '-S'] + command, stdin=PIPE, stderr=PIPE,
          universal_newlines=True)
        global sudo_prompt
        sudo_prompt = p.communicate(str(sudo_password) + '\n')[1]


text:
import re

from coalib.bearlib import deprecate_settings
from coalib.bearlib.spacing.SpacingHelper import SpacingHelper
from coalib.bears.LocalBear import LocalBear
from coalib.results.Result import Result
from coalib.settings.Setting import typed_list

class LineLengthBear(LocalBear):
    LANGUAGES = {'All'}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'coala-devel@googlegroups.com'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Formatting'}

    @deprecate_settings(indent_size='tab_width')
    def run(self,
            filename,
            file,
            max_line_length: int=79,
            indent_size: int=SpacingHelper.DEFAULT_TAB_WIDTH,
            ignore_length_regex: typed_list(str)=()):
        '''
        Yields results for all lines longer than the given maximum line length.

        :param max_line_length:     Maximum number of characters for a line,
                                    the newline character being excluded.
        :param indent_size:         Number of spaces per indentation level.
        :param ignore_length_regex: Lines matching each of the regular
                                    expressions in this list will be ignored.
        '''
        spacing_helper = SpacingHelper(indent_size)
        ignore_regexes = [re.compile(regex) for regex in ignore_length_regex]

        for line_number, line in enumerate(file):
            line = spacing_helper.replace_tabs_with_spaces(line)
            if len(line) > max_line_length + 1:
                if any(regex.search(line) for regex in ignore_regexes):
                    continue

                yield Result.from_values(
                    origin=self,
                    message='Line is longer than allowed.' +
                            ' ({actual} > {maximum})'.format(
                                actual=len(line)-1,
                                maximum=max_line_length),
                    file=filename,
                    line=line_number + 1,
                    column=max_line_length + 1,
                    end_line=line_number + 1,
                    end_column=len(line))


text:
import math
import random

import ps7_visualize
#from ps7_visualize import *
import pylab

# For Python 2.7:
from ps7_verify_movement27 import *

# If you get a "Bad magic number" ImportError, comment out what's above and
# uncomment this line (for Python 2.6):
# from ps7_verify_movement26 import testRobotMovement

# === Provided class Position
class Position(object):
    """
    A Position represents a location in a two-dimensional room.
    """
    def __init__(self, x, y):
        """
        Initializes a position with coordinates (x, y).
        """
        self.x = x
        self.y = y

    def getX(self):
        return self.x

    def getY(self):
        return self.y

    def getNewPosition(self, angle, speed):
        """
        Computes and returns the new Position after a single clock-tick has
        passed, with this object as the current position, and with the
        specified angle and speed.

        Does NOT test whether the returned position fits inside the room.

        angle: number representing angle in degrees, 0 <= angle < 360
        speed: positive float representing speed

        Returns: a Position object representing the new position.
        """
        old_x, old_y = self.getX(), self.getY()
        angle = float(angle)
        # Compute the change in position
        delta_y = speed * math.cos(math.radians(angle))
        delta_x = speed * math.sin(math.radians(angle))
        # Add that to the existing position
        new_x = old_x + delta_x
        new_y = old_y + delta_y
        return Position(new_x, new_y)

    def __str__(self):
        return "(%0.2f, %0.2f)" % (self.x, self.y)

# === Problem 1
class RectangularRoom(object):
    """
    A RectangularRoom represents a rectangular region containing clean or dirty
    tiles.

    A room has a width and a height and contains (width * height) tiles. At any
    particular time, each of these tiles is either clean or dirty.
    """
    def __init__(self, width, height):
        """
        Initializes a rectangular room with the specified width and height.

        Initially, no tiles in the room have been cleaned.

        width: an integer > 0
        height: an integer > 0
        """
        self.width       = width
        self.height      = height
        self.cleaned_tiles = []

    def cleanTileAtPosition(self, pos):
        """
        Mark the tile under the position POS as cleaned.

        Assumes that POS represents a valid position inside this room.

        pos: a Position
        """
        x = math.floor(pos.getX())
        y = math.floor(pos.getY())

        if (x,y) not in self.cleaned_tiles:
            self.cleaned_tiles.append((x,y))

    def isTileCleaned(self, m, n):
        """
        Return True if the tile (m, n) has been cleaned.

        Assumes that (m, n) represents a valid tile inside the room.

        m: an integer
        n: an integer
        returns: True if (m, n) is cleaned, False otherwise
        """
        return (m,n) in self.cleaned_tiles

    def getNumTiles(self):
        """
        Return the total number of tiles in the room.

        returns: an integer
        """
        return self.width * self.height

    def getNumCleanedTiles(self):
        """
        Return the total number of clean tiles in the room.

        returns: an integer
        """
#        return len(self.cleaned_tiles)
        cleanTiles = 0
        for i in range(self.width):
            for j in range(self.height):
                if self.isTileCleaned(i, j):
                    cleanTiles += 1
        return cleanTiles

    def getRandomPosition(self):
        """
        Return a random position inside the room.

        returns: a Position object.
        """
#        x = random.choice(range(self.width))
#        y = random.choice(range(self.height))
#
#        pos = Position(x,y)
#        return pos
        return Position(random.randint(0,self.width-1), random.randint(0,self.height-1))

    def isPositionInRoom(self, pos):
        """
        Return True if pos is inside the room.

        pos: a Position object.
        returns: True if pos is in the room, False otherwise.
        """
#        return (0 <= pos.getX() < self.width) and (0 <= pos.getY < self.height)
        if (0 <= pos.getX() < self.width) and (0 <= pos.getY() < self.height):
            return True
        else:
            return False

class Robot(object):
    """
    Represents a robot cleaning a particular room.

    At all times the robot has a particular position and direction in the room.
    The robot also has a fixed speed.

    Subclasses of Robot should provide movement strategies by implementing
    updatePositionAndClean(), which simulates a single time-step.
    """
    def __init__(self, room, speed):
        """
        Initializes a Robot with the given speed in the specified room. The
        robot initially has a random direction and a random position in the
        room. The robot cleans the tile it is on.

        room:  a RectangularRoom object.
        speed: a float (speed > 0)
        """
        self.room      = room
        self.direction = int(360 * random.random())
        self.pos       = self.room.getRandomPosition()#Position(room.width * random.random(), room.height * random.random())
        self.room.cleanTileAtPosition(self.pos)
        if speed > 0:
            self.speed = speed
        else:
            raise ValueError('Speed input must be greater than zero(0)')
#        self.pos       = getNewPosition(self.direction, self.speed)

    def getRobotPosition(self):
        """
        Return the position of the robot.

        returns: a Position object giving the robot's position.
        """
        return self.pos

    def getRobotDirection(self):
        """
        Return the direction of the robot.

        returns: an integer d giving the direction of the robot as an angle in
        degrees, 0 <= d < 360.
        """
        return self.direction

    def setRobotPosition(self, position):
        """
        Set the position of the robot to POSITION.

        position: a Position object.
        """
        if self.room.isPositionInRoom(position):
            self.pos = position
        else:
            raise ValueError('Position input is not in the room')

    def setRobotDirection(self, direction):
        """
        Set the direction of the robot to DIRECTION.

        direction: integer representing an angle in degrees
        """
        self.direction = direction

    def updatePositionAndClean(self):
        """
        Simulate the raise passage of a single time-step.

        Move the robot to a new position and mark the tile it is on as having
        been cleaned.
        """
        raise NotImplementedError # don't change this!

# === Problem 2
class StandardRobot(Robot):
    """
    A StandardRobot is a Robot with the standard movement strategy.

    At each time-step, a StandardRobot attempts to move in its current
    direction; when it would hit a wall, it *instead* chooses a new direction
    randomly.
    """
    def updatePositionAndClean(self):
        """
        Simulate the raise passage of a single time-step.

        Move the robot to a new position and mark the tile it is on as having
        been cleaned.
        """
        new_pos = self.pos.getNewPosition(self.direction, self.speed)
        if self.room.isPositionInRoom(new_pos):
            self.setRobotPosition(new_pos)
            self.room.cleanTileAtPosition(self.pos)
        else:
            self.setRobotDirection(int(360 * random.random()))
            self.updatePositionAndClean()
# Uncomment this line to see your implementation of StandardRobot in action!
##testRobotMovement(StandardRobot, RectangularRoom)

# === Problem 3
def runSimulation(num_robots, speed, width, height, min_coverage, num_trials,
                  robot_type):
    """
    Runs NUM_TRIALS trials of the simulation and returns the mean number of
    time-steps needed to clean the fraction MIN_COVERAGE of the room.

    The simulation is run with NUM_ROBOTS robots of type ROBOT_TYPE, each with
    speed SPEED, in a room of dimensions WIDTH x HEIGHT.

    num_robots: an int (num_robots > 0)
    speed: a float (speed > 0)
    width: an int (width > 0)
    height: an int (height > 0)
    min_coverage: a float (0 <= min_coverage <= 1.0)
    num_trials: an int (num_trials > 0)
    robot_type: class of robot to be instantiated (e.g. StandardRobot or
                RandomWalkRobot)
    """
    mean_time_taken = 0
    robots           = []

    for num in range(num_trials):
        '''optional visualization'''
        anim = ps7_visualize.RobotVisualization(num_robots, width, height)

        room = RectangularRoom(width, height)
        for robot in xrange(num_robots):
            robots.append(robot_type(room, speed))

        while room.getNumCleanedTiles() < (min_coverage * room.getNumTiles()):
            for robot in robots:
                robot.updatePositionAndClean()
            mean_time_taken += 1
            anim.update(room, robots)
        anim.done()
    return float(mean_time_taken/ num_trials)

runSimulation(10, 1.0, 30, 30, 0.8, 10, StandardRobot)

# === Problem 4
class RandomWalkRobot(Robot):
    """
    A RandomWalkRobot is a robot with the "random walk" movement strategy: it
    chooses a new direction at random at the end of each time-step.
    """
    def updatePositionAndClean(self):
        """
        Simulate the passage of a single time-step.

        Move the robot to a new position and mark the tile it is on as having
        been cleaned.
        """
        new_pos = self.pos.getNewPosition(self.direction, self.speed)
        if self.room.isPositionInRoom(new_pos):
            self.setRobotPosition(new_pos)
            self.room.cleanTileAtPosition(self.pos)
            self.setRobotDirection(int(360 * random.random()))
        else:
            self.setRobotDirection(int(360 * random.random()))
            self.updatePositionAndClean()

#runSimulation(10, 1.0, 15, 20, 0.8, 30, RandomWalkRobot)

def showPlot1(title, x_label, y_label):
    """
    What information does the plot produced by this function tell you?
    """
    num_robot_range = range(1, 11)
    times1 = []
    times2 = []
    for num_robots in num_robot_range:
        print "Plotting", num_robots, "robots..."
        times1.append(runSimulation(num_robots, 1.0, 2, 2, 0.8, 10, StandardRobot))
        times2.append(runSimulation(num_robots, 1.0, 2, 2, 0.8, 10, RandomWalkRobot))
    pylab.plot(num_robot_range, times1)
    pylab.plot(num_robot_range, times2)
    pylab.title(title)
    pylab.legend(('StandardRobot', 'RandomWalkRobot'))
    pylab.xlabel(x_label)
    pylab.ylabel(y_label)
    pylab.show()

def showPlot2(title, x_label, y_label):
    """
    What information does the plot produced by this function tell you?
    """
    aspect_ratios = []
    times1 = []
    times2 = []
    for width in [10, 20, 25, 10]:
        height = 300/width
        print "Plotting cleaning time for a room of width:", width, "by height:", height
        aspect_ratios.append(float(width) / height)
        times1.append(runSimulation(2, 1.0, width, height, 0.8, 200, StandardRobot))
        times2.append(runSimulation(2, 1.0, width, height, 0.8, 200, RandomWalkRobot))
    pylab.plot(aspect_ratios, times1)
    pylab.plot(aspect_ratios, times2)
    pylab.title(title)
    pylab.legend(('StandardRobot', 'RandomWalkRobot'))
    pylab.xlabel(x_label)
    pylab.ylabel(y_label)
    pylab.show()

# === Problem 5
#
# 1) Write a function call to showPlot1 that generates an appropriately-labeled
#     plot.
#
#       (... your call here ...)
#
#showPlot1("Plotting number robots...", 'x', 'y')
#showPlot2("Plotting number robots...", 'x', 'y')
#
# 2) Write a function call to showPlot2 that generates an appropriately-labeled
#     plot.
#
#       (... your call here ...)
#


text:
PROJECT_NAME := nRF51-TB6612FNG-test
OUTPUT_FILENAME := nrf51422_xxac_s110

export OUTPUT_FILENAME

MAKEFILE_NAME := $(MAKEFILE_LIST)
MAKEFILE_DIR := $(dir $(MAKEFILE_NAME) )

SDK_ROOT = /Users/mahesh/Documents/code/nRF51/nRF51_SDK_9.0.0_2e23562
TEMPLATE_PATH = $(SDK_ROOT)/components/toolchain/gcc
SOFTDEVICE_HEX = $(SDK_ROOT)/components/softdevice/s110/hex/s110_softdevice.hex

ifeq ($(OS),Windows_NT)
include $(TEMPLATE_PATH)/Makefile.windows
else
include $(TEMPLATE_PATH)/Makefile.posix
endif

MK := mkdir
RM := rm -rf

#echo suspend
ifeq ("$(VERBOSE)","1")
NO_ECHO :=
else
NO_ECHO := @
endif

# Toolchain commands
CC       		:= "$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-gcc"
AS       		:= "$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-as"
AR       		:= "$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-ar" -r
LD       		:= "$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-ld"
NM       		:= "$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-nm"
OBJDUMP  		:= "$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-objdump"
OBJCOPY  		:= "$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-objcopy"
SIZE    		:= "$(GNU_INSTALL_ROOT)/bin/$(GNU_PREFIX)-size"

#function for removing duplicates in a list
remduplicates = $(strip $(if $1,$(firstword $1) $(call remduplicates,$(filter-out $(firstword $1),$1))))

#source common to all targets
C_SOURCE_FILES += \
$(abspath ../../../main.c) \
$(abspath ../../../ble_init.c) \
$(SDK_ROOT)/components/libraries/util/app_error.c \
$(SDK_ROOT)/components/libraries/fifo/app_fifo.c \
$(SDK_ROOT)/components/libraries/trace/app_trace.c \
$(SDK_ROOT)/components/libraries/util/nrf_assert.c \
$(SDK_ROOT)/components/libraries/uart/retarget.c \
$(SDK_ROOT)/components/libraries/pwm/app_pwm.c \
$(SDK_ROOT)/components/drivers_nrf/uart/app_uart_fifo.c \
$(SDK_ROOT)/components/drivers_nrf/hal/nrf_delay.c \
$(SDK_ROOT)/components/drivers_nrf/common/nrf_drv_common.c \
$(SDK_ROOT)/components/drivers_nrf/pstorage/pstorage.c \
$(SDK_ROOT)/components/drivers_nrf/gpiote/nrf_drv_gpiote.c \
$(SDK_ROOT)/components/drivers_nrf/ppi/nrf_drv_ppi.c \
$(SDK_ROOT)/components/drivers_nrf/timer/nrf_drv_timer.c \
$(SDK_ROOT)/components/libraries/timer/app_timer.c \
$(SDK_ROOT)/components/ble/common/ble_advdata.c \
$(SDK_ROOT)/components/ble/ble_advertising/ble_advertising.c \
$(SDK_ROOT)/components/ble/ble_services/ble_bas/ble_bas.c \
$(SDK_ROOT)/components/ble/common/ble_conn_params.c \
$(SDK_ROOT)/components/ble/ble_services/ble_dis/ble_dis.c \
$(SDK_ROOT)/components/ble/ble_services/ble_hrs/ble_hrs.c \
$(SDK_ROOT)/components/ble/common/ble_srv_common.c \
$(SDK_ROOT)/components/ble/device_manager/device_manager_peripheral.c \
$(SDK_ROOT)/components/ble/ble_services/ble_nus/ble_nus.c \
$(SDK_ROOT)/components/ble/ble_radio_notification/ble_radio_notification.c \
$(SDK_ROOT)/components/toolchain/system_nrf51.c \
$(SDK_ROOT)/components/softdevice/common/softdevice_handler/softdevice_handler.c

#assembly files common to all targets
ASM_SOURCE_FILES  = $(SDK_ROOT)/components/toolchain/gcc/gcc_startup_nrf51.s

#assembly files common to all targets
LIBS  = $(SDK_ROOT)/external/rtx/source/GCC/libRTX_CM0.a

#includes common to all targets
INC_PATHS  = -I$(abspath ../../../config)
INC_PATHS += -I$(SDK_ROOT)/components/libraries/fifo
INC_PATHS += -I$(SDK_ROOT)/components/libraries/util
INC_PATHS += -I$(SDK_ROOT)/components/libraries/gpiote
INC_PATHS += -I$(SDK_ROOT)/components/libraries/pwm
INC_PATHS += -I$(SDK_ROOT)/components/libraries/timer
INC_PATHS += -I$(SDK_ROOT)/components/libraries/trace
INC_PATHS += -I$(SDK_ROOT)/components/drivers_nrf/hal
INC_PATHS += -I$(SDK_ROOT)/components/drivers_nrf/timer
INC_PATHS += -I$(SDK_ROOT)/components/drivers_nrf/ppi
INC_PATHS += -I$(SDK_ROOT)/components/drivers_nrf/pstorage
INC_PATHS += -I$(SDK_ROOT)/components/drivers_nrf/uart
INC_PATHS += -I$(SDK_ROOT)/components/drivers_nrf/gpiote
INC_PATHS += -I$(SDK_ROOT)/components/drivers_nrf/config
INC_PATHS += -I$(SDK_ROOT)/components/drivers_nrf/common
INC_PATHS += -I$(SDK_ROOT)/components/ble/common
INC_PATHS += -I$(SDK_ROOT)/components/ble/device_manager
INC_PATHS += -I$(SDK_ROOT)/components/ble/ble_services/ble_dis
INC_PATHS += -I$(SDK_ROOT)/components/ble/ble_services/ble_nus
INC_PATHS += -I$(SDK_ROOT)/components/ble/ble_advertising
INC_PATHS += -I$(SDK_ROOT)/components/ble/ble_services/ble_bas
INC_PATHS += -I$(SDK_ROOT)/components/ble/ble_services/ble_hrs
INC_PATHS += -I$(SDK_ROOT)/components/ble/ble_radio_notification
INC_PATHS += -I$(SDK_ROOT)/components/device
INC_PATHS += -I$(SDK_ROOT)/components/toolchain/gcc
INC_PATHS += -I$(SDK_ROOT)/components/toolchain
INC_PATHS += -I$(SDK_ROOT)/components/softdevice/s110/headers
INC_PATHS += -I$(SDK_ROOT)/components/softdevice/common/softdevice_handler
INC_PATHS += -I$(SDK_ROOT)/examples/bsp
INC_PATHS += -I$(SDK_ROOT)/external/rtx/include

OBJECT_DIRECTORY = _build
LISTING_DIRECTORY = $(OBJECT_DIRECTORY)
OUTPUT_BINARY_DIRECTORY = $(OBJECT_DIRECTORY)

# Sorting removes duplicates
BUILD_DIRECTORIES := $(sort $(OBJECT_DIRECTORY) $(OUTPUT_BINARY_DIRECTORY) $(LISTING_DIRECTORY) )

#flags common to all targets
CFLAGS  = -DBOARD_PCA10028
CFLAGS += -D__STACK_SIZE=1024
CFLAGS += -DSOFTDEVICE_PRESENT
CFLAGS += -DNRF51
CFLAGS += -DS110
CFLAGS += -D__HEAP_SIZE=0
CFLAGS += -DBLE_STACK_SUPPORT_REQD
CFLAGS += -DRTX
CFLAGS += -mcpu=cortex-m0
CFLAGS += -mthumb -mabi=aapcs --std=gnu99
CFLAGS += -Wall -Werror -O3
CFLAGS += -mfloat-abi=soft
# keep every function in separate section. This will allow linker to dump unused functions
CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
CFLAGS += -fno-builtin --short-enums

# keep every function in separate section. This will allow linker to dump unused functions
LDFLAGS += -Xlinker -Map=$(LISTING_DIRECTORY)/$(OUTPUT_FILENAME).map
LDFLAGS += -mthumb -mabi=aapcs -L $(TEMPLATE_PATH) -T$(LINKER_SCRIPT)
LDFLAGS += -mcpu=cortex-m0
# let linker to dump unused sections
LDFLAGS += -Wl,--gc-sections
# use newlib in nano version
LDFLAGS += --specs=nano.specs -lc -lnosys
# for printf float support
LDFLAGS += -u _printf_float

# Assembler flags
ASMFLAGS += -x assembler-with-cpp
ASMFLAGS += -DBOARD_PCA10028
ASMFLAGS += -D__STACK_SIZE=1024
ASMFLAGS += -DSOFTDEVICE_PRESENT
ASMFLAGS += -DNRF51
ASMFLAGS += -DS110
ASMFLAGS += -D__HEAP_SIZE=0
ASMFLAGS += -DBLE_STACK_SUPPORT_REQD
ASMFLAGS += -DRTX
#default target - first one defined
default: clean nrf51422_xxac_s110

#building all targets
all: clean
	$(NO_ECHO)$(MAKE) -f $(MAKEFILE_NAME) -C $(MAKEFILE_DIR) -e cleanobj
	$(NO_ECHO)$(MAKE) -f $(MAKEFILE_NAME) -C $(MAKEFILE_DIR) -e nrf51422_xxac_s110

#target for printing all targets
help:
	@echo following targets are available:
	@echo 	nrf51422_xxac_s110
	@echo 	flash_softdevice

C_SOURCE_FILE_NAMES = $(notdir $(C_SOURCE_FILES))
C_PATHS = $(call remduplicates, $(dir $(C_SOURCE_FILES) ) )
C_OBJECTS = $(addprefix $(OBJECT_DIRECTORY)/, $(C_SOURCE_FILE_NAMES:.c=.o) )

ASM_SOURCE_FILE_NAMES = $(notdir $(ASM_SOURCE_FILES))
ASM_PATHS = $(call remduplicates, $(dir $(ASM_SOURCE_FILES) ))
ASM_OBJECTS = $(addprefix $(OBJECT_DIRECTORY)/, $(ASM_SOURCE_FILE_NAMES:.s=.o) )

vpath %.c $(C_PATHS)
vpath %.s $(ASM_PATHS)

OBJECTS = $(C_OBJECTS) $(ASM_OBJECTS)

nrf51422_xxac_s110: OUTPUT_FILENAME := nrf51422_xxac_s110
nrf51422_xxac_s110: LINKER_SCRIPT=nRF51-TB6612FNG-test.ld
nrf51422_xxac_s110: $(BUILD_DIRECTORIES) $(OBJECTS)
	@echo Linking target: $(OUTPUT_FILENAME).out
	$(NO_ECHO)$(CC) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out
	$(NO_ECHO)$(MAKE) -f $(MAKEFILE_NAME) -C $(MAKEFILE_DIR) -e finalize

## Create build directories
$(BUILD_DIRECTORIES):
	echo $(MAKEFILE_NAME)
	$(MK) $@

# Create objects from C SRC files
$(OBJECT_DIRECTORY)/%.o: %.c
	@echo Compiling file: $(notdir $<)
	$(NO_ECHO)$(CC) $(CFLAGS) $(INC_PATHS) -c -o $@ $<

# Assemble files
$(OBJECT_DIRECTORY)/%.o: %.s
	@echo Compiling file: $(notdir $<)
	$(NO_ECHO)$(CC) $(ASMFLAGS) $(INC_PATHS) -c -o $@ $<

# Link
$(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out: $(BUILD_DIRECTORIES) $(OBJECTS)
	@echo Linking target: $(OUTPUT_FILENAME).out
	$(NO_ECHO)$(CC) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out

## Create binary .bin file from the .out file
$(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).bin: $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out
	@echo Preparing: $(OUTPUT_FILENAME).bin
	$(NO_ECHO)$(OBJCOPY) -O binary $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).bin

## Create binary .hex file from the .out file
$(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).hex: $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out
	@echo Preparing: $(OUTPUT_FILENAME).hex
	$(NO_ECHO)$(OBJCOPY) -O ihex $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).hex

finalize: genbin genhex echosize

genbin:
	@echo Preparing: $(OUTPUT_FILENAME).bin
	$(NO_ECHO)$(OBJCOPY) -O binary $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).bin

## Create binary .hex file from the .out file
genhex:
	@echo Preparing: $(OUTPUT_FILENAME).hex
	$(NO_ECHO)$(OBJCOPY) -O ihex $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).hex

echosize:
	-@echo ""
	$(NO_ECHO)$(SIZE) $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out
	-@echo ""

clean:
	$(RM) $(BUILD_DIRECTORIES) *.jlink

cleanobj:
	$(RM) $(BUILD_DIRECTORIES)/*.o

GDB_PORT_NUMBER := 9992

FLASH_START_ADDR = $(shell $(OBJDUMP) -h $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out -j .text | grep .text | awk '{print $$4}')

JLINK_OPTS = -device nrf51422_xxaa -if swd -speed 4000
JLINK_GDB_OPTS = -noir
JLINKD_GDB = JLinkGDBServer $(JLINK_GDB_OPTS)

# flashing windows vs. posix
ifeq ($(OS),Windows_NT)
JLINK = JLink $(JLINK_OPTS)
else
JLINK = JLinkExe $(JLINK_OPTS)
endif # flashing windows vs. posix

flash: flash.jlink
	$(JLINK) flash.jlink

flash.jlink:
	printf "loadbin $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).bin $(FLASH_START_ADDR)\nr\ng\nexit\n" > flash.jlink

flash_softdevice: flashsd.jlink
	$(JLINK) flashsd.jlink

flashsd.jlink:
	printf "loadbin $(SOFTDEVICE_HEX) 0\nr\ng\nexit\n" > flashsd.jlink

flash-check:
	printf "loadbin $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).bin $(FLASH_START_ADDR)\nr\ng\nexit\n"

erase-all: erase-all.jlink
	$(JLINK) erase-all.jlink

# Write to NVMC to enable erase, do erase all, wait for completion. reset
erase-all.jlink:
	printf "w4 4001e504 2\nw4 4001e50c 1\nsleep 100\nr\nexit\n" > erase-all.jlink

run-debug:
	$(JLINKD_GDB) $(JLINK_OPTS) $(JLINK_GDB_OPTS) -port $(GDB_PORT_NUMBER)

.PHONY:  flash-jlink flash.jlink erase-all erase-all.jlink run-debug


text:
"""List virtual server credentials."""
# :license: MIT, see LICENSE for more details.

import click

import SoftLayer
from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer.CLI import helpers

@click.command()
@click.argument('identifier')
@environment.pass_env
def cli(env, identifier):
    """List virtual server credentials."""

    vsi = SoftLayer.VSManager(env.client)
    vs_id = helpers.resolve_id(vsi.resolve_ids, identifier, 'VS')
    instance = vsi.get_instance(vs_id)

    table = formatting.Table(['username', 'password'])
    for item in instance['operatingSystem']['passwords']:
        table.add_row([item['username'], item['password']])
    env.fout(table)