#pragma once

#include <saas/deploy_manager/storage/abstract.h>
#include <saas/deploy_manager/config/config.h>
#include <library/cpp/cgiparam/cgiparam.h>

class TUserAccessModule : public NRTYDeploy::IUserAccessControl {
public:
    TUserAccessModule(const TCgiParameters& cgi, const TString& command, NRTYDeploy::IVersionedStorage& storage, const TDeployManagerConfig& config);
    virtual const TPermissions& GetPermissions() const {
        return Permisions;
    }

    virtual TString GetCookie(const TString& user) const;
    virtual TString GetUserConfig(const TString& user, bool group) const;
    virtual void SetUserConfig(const TString& config, const TString& user, bool group);

private:
    bool ReadAccessConfig();
    TString GetUser(const TString& cookie);
    void ReadPermissionsUser(const TString& command, const NJson::TJsonValue& section);
    void ReadPermissionsCommand(const TString& command, const NJson::TJsonValue& section);

private:

    struct TAllowedResources : public TUsedResources {
        void AddPermissions(TPermissions& result) const;
        void Serialize(NJson::TJsonValue& result, const TString& name) const;
        bool Deserialize(const NJson::TJsonValue& section);
    };

    class TAccessConfig;

    class TGroupData {
    public:
        TGroupData(TAccessConfig& owner);
        void Serialize(NJson::TJsonValue& result) const;
        bool Deserialize(const NJson::TJsonValue& section);
        void FillMyServices(TPermissions& result) const;
        void FillResources(TPermissions& result, const TString& command) const;
    private:
        typedef THashMap<TString, TAllowedResources> TCommandToResources;
        typedef THashSet<TString> TGroups;

        TCommandToResources Commands;
        TGroups Groups;
        TServicesSet MyServices;
        TAccessConfig& Owner;
    };

    class TUserData : public TGroupData {
    public:
        TUserData(TAccessConfig& owner);

        const TString& GetUserName() const {
            return UserName;
        }
        void SetUserName(const TString& name) {
            UserName = name;
        }
    private:
        TString UserName;
    };

    class TAccessConfig {
    public:
        TAccessConfig(const TString& privateKey);
        void Serialize(NRTYDeploy::IVersionedStorage& storage) const;
        TString Serialize() const;
        bool Deserialize(NRTYDeploy::IVersionedStorage& storage);
        const TUserData& GetUser(const TString& cookie) const;
        const TGroupData* GetGroup(const TString& group) const;
        TString GetCookie(const TString& user) const;
        void SetUserData(const NJson::TJsonValue& conf, const TString& user);
        void SetGroupData(const NJson::TJsonValue& conf, const TString& group);

    private:
        typedef THashMap<TString, TUserData> TUsers;
        typedef THashMap<TString, TGroupData> TGroups;

        TUsers Users;
        TGroups Groups;
        TString PrivateKey;
    };

private:
    NRTYDeploy::IVersionedStorage& Storage;
    TAccessConfig AccessConfig;
    TPermissions Permisions;
};
