#include "script.h"
#include <saas/deploy_manager/scripts/common/scripts_helper.h>
#include <saas/deploy_manager/server/client/client.h>
#include <saas/util/external/diff.h>
#include <library/cpp/json/json_reader.h>
#include <library/cpp/logger/global/global.h>

namespace NRTYDeploy {

    bool TScriptLocker::Process(IDeployInfoRequest& request) {
        const TString lockName = request.GetRD().CgiParam.Get("lock_name");
        const TString lockInfo = request.GetRD().CgiParam.Get("lock_info");
        const TString fullLockName = "/locks/persistent/" + lockName;
        TString action = request.GetRD().CgiParam.Get("action");

        if (!lockName && action != "info") {
            request.Output() << "HTTP/1.1 400 \r\n\r\n";
            request.Output() << "cgi lock_name is not correct";
            return false;
        }

        TString value;
        if (action == "info" && !lockName) {
            TVector<TString> locks;
            if (request.GetStorage().GetNodes(fullLockName, locks)) {
                NJson::TJsonValue result(NJson::JSON_MAP);
                for (ui32 i = 0; i < locks.size(); ++i) {
                    if (request.GetStorage().GetValue(fullLockName + "/" + locks[i], value))
                        result.InsertValue(locks[i], value);
                    else
                        result.InsertValue(locks[i], "CAN'T READ");
                }
                request.Output() << "HTTP/1.1 200 \r\n\r\n";
                request.Output() << NJson::WriteJson(&result);
                return true;
            }
            else {
                request.Output() << "HTTP/1.1 400 \r\n\r\n";
                request.Output() << "Can't read locks base";
                return false;
            }
        }

        NRTYDeploy::TAbstractLock::TPtr lock = !!lockName ? request.GetStorage().WriteLockNode(lockName, TDuration::Seconds(10)) : nullptr;
        if (!!lock && lock->IsLocked()) {
            if (action == "acquire") {
                if (request.GetStorage().GetValue(fullLockName, value)) {
                    if (value == lockInfo) {
                        request.Output() << "HTTP/1.1 200 \r\n\r\n";
                        request.Output() << "ALREADY LOCKED";
                    }
                    else {
                        request.Output() << "HTTP/1.1 500 \r\n\r\n";
                        request.Output() << "RESOURCE BUSY FOR " << value;
                    }
                }
                else {
                    request.GetStorage().SetValue(fullLockName, lockInfo);
                    request.Output() << "HTTP/1.1 200 \r\n\r\n";
                    request.Output() << lockName << " LOCKED";
                }
            } else
            if (action == "release") {
                if (request.GetStorage().GetValue(fullLockName, value)) {
                    if (value == lockInfo) {
                        CHECK_WITH_LOG(request.GetStorage().RemoveNode(fullLockName));
                        request.Output() << "HTTP/1.1 200 \r\n\r\n";
                        request.Output() << "OK";
                    }
                    else {
                        request.Output() << "HTTP/1.1 500 \r\n\r\n";
                        request.Output() << "RESOURCE BUSY NOT FOR " << lockInfo << "(" << value << ")";
                    }
                }
                else {
                    request.Output() << "HTTP/1.1 200 \r\n\r\n";
                    request.Output() << "NOT LOCKED";
                }
            }
            else if (action == "info") {
                NJson::TJsonValue result(NJson::JSON_MAP);
                if (request.GetStorage().GetValue(fullLockName, value))
                    result.InsertValue(lockName, value);
                else
                    result.InsertValue(lockName, "CAN'T READ");
                request.Output() << "HTTP/1.1 200 \r\n\r\n";
                request.Output() << NJson::WriteJson(&result);
            }
            else {
                request.Output() << "HTTP/1.1 400 \r\n\r\n";
                request.Output() << "Incorrect action " << action;
                return false;
            }

        }
        else {
            request.Output() << "HTTP/1.1 500 \r\n\r\n";
            request.Output() << "CAN'T TAKE EPHEMERAL LOCK " << lockName;
        }

        return true;
    };

    IScript::TFactory::TRegistrator<TScriptLocker> TScriptLocker::Registrator("locker");
}
