#include "client_settings.h"
#include <library/cpp/config/sax.h>

namespace NModSsl {
    THolder<TClientSettings> ParseSettings(NConfig::IConfig* conf) {
        struct TClientSettingsParser final : public NConfig::IConfig::IFunc {
            TClientSettingsParser(NConfig::IConfig* config) {
                config->ForEach(this);
            }

            START_PARSE {
                ON_KEY("crl", Crl) {
                    return;
                }

                ON_KEY("verify_depth", VerifyDepth) {
                    return;
                }

                ON_KEY("verify_peer", VerifyPeer) {
                    return;
                }

                ON_KEY("verify_once", VerifyOnce) {
                    return;
                }

                ON_KEY("fail_if_no_peer_cert", FailIfNoPeerCert) {
                    return;
                }
            } END_PARSE

            TString Crl;
            int VerifyDepth = 3;
            bool VerifyPeer = true;
            bool VerifyOnce = false;
            bool FailIfNoPeerCert = true;
        } parser(conf);

        if (!parser.VerifyPeer) {
            if (parser.VerifyOnce) {
                // throw instead of ythrow for not printing lines twice
                ythrow NConfig::TConfigParseError() << "set \"verify_peer\" if setting \"verify_once\"";
            }
            if (parser.FailIfNoPeerCert) {
                // throw instead of ythrow for not printing lines twice
                ythrow NConfig::TConfigParseError() << "set \"verify_peer\" if setting \"fail_if_no_peer_cert\"";
            }
        }
        if (parser.VerifyDepth < 0) {
            ythrow NConfig::TConfigParseError() << "bad \"verify_depth\" of " << parser.VerifyDepth;
        }

        int mode = parser.VerifyPeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE;
        if (parser.VerifyOnce) {
            mode |= SSL_VERIFY_CLIENT_ONCE;
        }
        if (parser.FailIfNoPeerCert) {
            mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
        }
        // We cant call MakeHolder because it is not our friend
        // But it's still exception safe
        return THolder<TClientSettings>(new TClientSettings(mode, parser.VerifyDepth, std::move(parser.Crl)));
    }
}
