if (ServerParams.getParam("enableOAuth") == "") {
    ServerParams.setParam("enableOAuth", "true");
}

if (ServerParams.getParam("useWebdav") == "") {
    ServerParams.setParam("useWebdav", "false");
    ServerParams.setParam("token", "");
    ServerParams.setParam("tokenType", "");
}

login <- "";
enableOAuth <- true;
baseUrl <-"https://cloud-api.yandex.net/v1/disk/resources/";
clientId <- "a49c34035aa8418d9a77ff24e0660719";
clientSecret <- "f9496665e3494022a00b7dbe9a5f0d9e";

function regex_simple(data, regStr, start) {
    local ex = regexp(regStr);
    local res = ex.capture(data, start);
    local resultStr = "";
    if (res != null){
        resultStr = data.slice(res[1].begin, res[1].end);
    }
        return resultStr;
}

function reg_replace(str, pattern, replace_with) {
    local resultStr = str;
    local res;
    local start = 0;

    while( (res = resultStr.find(pattern,start)) != null ) {

        resultStr = resultStr.slice(0,res) +replace_with+ resultStr.slice(res + pattern.len());
        start = res + replace_with.len();
    }
    return resultStr;
}

/*function _UrlEncodePath(str) {
    local res = "";
    local start = 0;
    local pos;
    while ((pos = str.find("/", start)) != null ) {
        res += nm.urlEncode(str.slice(start, pos)) + "/";
        start = pos + 1;
    }
    res += nm.urlEncode(str.slice(start));

    return res;
}*/

function _CheckResponse() {
    if ( nm.responseCode() == 0 || (nm.responseCode() >= 400 && nm.responseCode() <= 499)) {
        WriteLog("error", "Response code " + nm.responseCode() + "\r\n" + nm.errorString() );
        return 0;
    }
    return 1;
}

function _IsSuccessCode(code) {
    return ( code >= 200 && code < 300);
}

function _GetAuthorizationString() {
    return "OAuth " + ServerParams.getParam("token");
}

function _ParseAlbumList(data,list,parentid)
{
    local start = 0;

    while(1) {
        local title="",id="",summary="";
        local response = "";

        start += response.len();
        local ex = regexp("<d:response>");
        local res = ex.search(data, start);
        local link = "";
        local album = CFolderItem();
        if(res != null){
            start = res.end;
            ex = regexp("</d:response>");
            res = ex.search(data, start);
            if (res != null){
                response = data.slice(start, res.end);
                local href = regex_simple(response,"<d:href>(.+)</d:href>",0);

                local resourceType =  regex_simple(response,"<d:resourcetype>(.+)</d:resourcetype>",0);
                if (regex_simple(response, "(d:collection)", 0) != "") {
                    local displayName = regex_simple(response,"<d:displayname>(.+)</d:displayname>",0);
                    album.setId(href);
                    if (href == "/" ) {
                        displayName += " (/)";
                    }
                    album.setTitle(displayName);
                    album.setSummary("");
                    list.AddFolderItem(album);
                }
            } 	else {
                break;
            }
        }
        else break;
    }
    return 1;
}

function _LoadAlbumList(list) {
    if (_UseRestApi()) {
        nm.addQueryHeader("Authorization", _GetAuthorizationString());
        nm.addQueryHeader("Accept", "application/json");
        nm.enableResponseCodeChecking(false);
        nm.doGet("https://cloud-api.yandex.net:443/v1/disk");// test request

        local code = nm.responseCode();
        if (code == 401){
            ServerParams.setParam("token","");
            throw "unauthorized_exception";
        }

        local url = "https://cloud-api.yandex.net:443/v1/disk/resources?path=%2F&limit=100";
        nm.addQueryHeader("Authorization", _GetAuthorizationString());
        nm.addQueryHeader("Accept", "application/json");
        nm.doGet(url);
        code = nm.responseCode();

        if (code == 200) {
            local folder = CFolderItem();
            folder.setId("/");
            folder.setTitle("/ (root)");
            folder.setSummary("");
            list.AddFolderItem(folder);
            local res = ParseJSON(nm.responseBody());
            local itemsCount = res._embedded.items.len();
            for ( local i = 0; i< itemsCount; i++ ) {
                local item = res._embedded.items[i];
                if ( item.type != "dir" ) {
                    continue;
                }
                local folder = CFolderItem();
                local path = item.path;
                path = reg_replace(path, "disk:", "") + "/";
                folder.setId(path);
                folder.setTitle(item.name);
                folder.setSummary("");
                list.AddFolderItem(folder);
            }
            return 1;
        }
        return 0;
    }

    local url = "https://webdav.yandex.ru/";

    nm.setUrl(url);
    nm.addQueryHeader("Authorization",_GetAuthorizationString());
    nm.addQueryHeader("Connection", "close");
    nm.addQueryHeader("Depth", "1");
    nm.setMethod("PROPFIND");
    nm.doGet(url);

    if ( _IsSuccessCode(nm.responseCode()) ) {
        return _ParseAlbumList(nm.responseBody(), list, "");
    } else if (nm.responseCode() == 401) {
        WriteLog("error", "Authentication failed for username '" + ServerParams.getParam("Login") + "'.\r\nResponse code: "+ nm.responseCode());
        return 0;
    }

    return 0;
}

function GetFolderList(list) {
    return _LoadAlbumList(list);
}

function CreateFolder(parentAlbum, album) {
    local folderName = album.getTitle();
    if (folderName == "") {
        return 0;
    }
    local url = "https://webdav.yandex.ru/" + nm.urlEncode(folderName);

    nm.setUrl(url);
    nm.addQueryHeader("Authorization",_GetAuthorizationString());
    nm.addQueryHeader("Connection", "close");
    nm.addQueryHeader("Depth", "1");
    nm.setMethod("MKCOL");
    nm.doGet(url);

    if (nm.responseCode() != 201) { // HTTP Status code 201 = Created
        return 0;
    }

    return 1;
}

function _GetAuthentificationErrorString(code) {
    return "Authentication failed for username '" + ServerParams.getParam("Login") + "'.\r\nResponse code: " + code;
}

function _CheckIfExists(filename){
    local url = "https://webdav.yandex.ru" + filename;

    nm.enableResponseCodeChecking(false);

    nm.setUrl(url);
    nm.addQueryHeader("Authorization",_GetAuthorizationString());
    nm.addQueryHeader("Connection", "close");
    nm.addQueryHeader("Depth", "1");
    nm.addQueryHeader("Content-Type", "application/xml");
    nm.setMethod("PROPFIND");
    nm.addQueryHeader("Transfer-Encoding", "");
    nm.doUpload("", "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                    "<propfind xmlns=\"DAV:\">"+
                    "<prop>"+
                    "<myprop xmlns=\"mynamespace\"/>"+
                    "</prop>"+
                    "</propfind>"
                    );

    nm.enableResponseCodeChecking(true);

    if (nm.responseCode() == 401) {
        throw _GetAuthentificationErrorString(nm.responseCode());
        return 0;
    }
    return (nm.responseCode() >= 200 && nm.responseCode() < 300);
}

function _CheckResponseCode() {
    if ( !_IsSuccessCode(nm.responseCode()) ) {
        local errorMessage = "";
        if ( nm.responseCode() == 401 ) {
            errorMessage += "Authentication failed for username '" + ServerParams.getParam("Login") + "'.";
        } else {
            errorMessage += "\r\nResponse: " + nm.responseBody();
        }

        errorMessage  += "\r\nResponse code: "+ nm.responseCode();
        throw errorMessage;
    }
}

function _UseRestApi() {
    local l = ServerParams.getParam("useWebdav");
    return (l == "") || ( l != "true" && l != "yes" && l != "1");
}

function Authenticate() {
    if ( enableOAuth ) {
        local token = ServerParams.getParam("token");
        local tokenType = ServerParams.getParam("tokenType");
        if ( token != "" && ServerParams.getParam("PrevLogin") == ServerParams.getParam("Login") ) {
            if ( tokenType == "oauth" ) {
                local OAuthLogin = ServerParams.getParam("OAuthLogin");
                if ( OAuthLogin != "") {
                    login = OAuthLogin;
                }
            }
            return 1;
        }

        ShellOpenUrl("https://oauth.yandex.ru/authorize?response_type=code&client_id=a49c34035aa8418d9a77ff24e0660719");

        local confirmCode = InputDialog(tr("yandexdisk.confirmation.text", "You need to need to sign in to your Yandex.Disk account in web browser which just have opened and then copy confirmation code into the text field below. Please enter confirmation code:"), "");
        if ( confirmCode != "" ) {
            nm.setUrl("https://oauth.yandex.ru/token");
            nm.addQueryParam("grant_type", "authorization_code");
            nm.addQueryParam("code", confirmCode);
            //nm.addQueryParam("client_id", "28d8d9c854554812ad8b60c150375462");
            //nm.addQueryParam("client_secret", "7d6fee42d583498ea7740bcf8b753197");
            nm.addQueryParam("client_id", clientId);
            nm.addQueryParam("client_secret", clientSecret);
            local deviceId = GetDeviceId();
            if (deviceId != "") {
                nm.addQueryParam("device_id", deviceId);
            }
            local deviceName = GetDeviceName();
            if (deviceName != "") {
                nm.addQueryParam("device_name", deviceName);
            }
            nm.doPost("");

            if ( !_CheckResponse() ) {
                return 0;
            }
            local t = ParseJSON(nm.responseBody());

            local accessToken = "";
            if ("access_token" in t) {
                accessToken = t.access_token;
            }

            if (accessToken != "") {
                token = 	accessToken;
                tokenType = "oauth";
                ServerParams.setParam("token", token);
                ServerParams.setParam("tokenType", tokenType);
                ServerParams.setParam("PrevLogin", ServerParams.getParam("Login"));

                return 1;
            } else {
                WriteLog("error", "Unable to get OAuth token!");
                return 0;
            }
        }
    }

    login <- ServerParams.getParam("Login");
    local pass = ServerParams.getParam("Password");

    if(login == "" || pass=="")
    {
        WriteLog("error","E-mail and password should not be empty!");
        return 0;
    }

    return 0;
}

function IsAuthenticated() {
    if (ServerParams.getParam("token") != "") {
        return 1;
    }
    return 0;
}

function DoLogout() {
    local token = ServerParams.getParam("token");
    if (token == "") {
        return 0;
    }
    local url = "https://oauth.yandex.ru/revoke_token";
    nm.setUrl(url);
    nm.addQueryParam("access_token", token);
    nm.addQueryParam("client_id", clientId);
    nm.addQueryParam("client_secret", clientSecret);

    nm.doPost("");

    if (nm.responseCode() == 200) {
        ServerParams.setParam("token", "");
        return 1;
    } else {
        local t = ParseJSON(nm.responseBody());
        if ("error" in t && t.error == "unsupported_token_type") {
            // Token cannot be revoked, because token was issued without device_id
            // Just remove it from local storage
            ServerParams.setParam("token", "");
            return 1;
        }
    }
    return 0;
}

function UploadFile(FileName, options) {
    local ansiFileName = ExtractFileName(FileName);
    local fileSize = GetFileSize(FileName);

    try {
        local task = options.getTask();
        ansiFileName = task.getDisplayName(); // ensure that this field is filled up correctly
    } catch ( ex ) {
    }

    local folder = options.getFolderID();
    if ( folder == "" ) {
        folder = "/";
    }

    local initialRemotePath = folder + (ansiFileName);
    local remotePath = folder + ansiFileName;
    local remotePathEncoded = folder + nm.urlEncode(ansiFileName);
    local i = 2;

    if (_UseRestApi()) {
        local url = baseUrl + "upload/?path=" + nm.urlEncode(remotePath);

        nm.addQueryHeader("Accept", "application/json");
        nm.addQueryHeader("Authorization", _GetAuthorizationString());
        try {
            nm.enableResponseCodeChecking(false);
        } catch ( ex ) {}
        nm.doGet(url);

        if (nm.responseCode() == 401) { // not authorized
            ServerParams.setParam("token", "");
            throw "unauthorized_exception";
            //try again
            /*nm.addQueryHeader("Accept", "application/json");
            nm.addQueryHeader("Authorization", _GetAuthorizationString());
            nm.doGet(url);*/
        }

        while ( nm.responseCode() == 409 ) {
            local ext = GetFileExtension(ansiFileName);
            local suffix = i.tostring();
            if ( i > 5 ) {
                suffix = md5( random().tostring()).slice(0,4);
            }
            local filename = ansiFileName.slice(0,ansiFileName.len()-ext.len()-1) + "_" + suffix;

            if ( ext.len() ) {
                filename += "." + ext;
            }
            remotePath = folder + filename;
            nm.setUrl(baseUrl + "upload/?path=" + nm.urlEncode(remotePath));
            nm.addQueryHeader("Accept", "application/json");

            nm.addQueryHeader("Authorization", _GetAuthorizationString());
            try {
                nm.enableResponseCodeChecking(false);
            } catch ( ex ) {}
            nm.doGet("");
            i++;
            if ( i > 10 ) {
                return 0;
            }
        }

        try {
            nm.enableResponseCodeChecking(true);
        } catch ( ex ) {}

        if ( nm.responseCode() == 200 ) {
            local data = nm.responseBody();
            local href = null;
            local method = "PUT";

            local t = ParseJSON(data);
            href = t.href;
            method = t.method;

            if (href == null || href == "") {
                return 0;
            }
            nm.setUrl(href);
            nm.setMethod(method);
            nm.addQueryHeader("Transfer-Encoding", "");
            nm.addQueryHeader("Authorization", _GetAuthorizationString());
            nm.doUpload(FileName, "");
            if (nm.responseCode() != 201) {
                WriteLog("error", "Failed to upload file " + ExtractFileName(FileName)+".");
                return 0;
            }
            nm.setUrl(baseUrl + "publish?path=" + nm.urlEncode(remotePath));
            nm.addQueryHeader("Accept", "application/json");
            //nm.addQueryHeader("Content-Length", "0");
            nm.addQueryHeader("Transfer-Encoding", "");
            nm.addQueryHeader("Authorization",_GetAuthorizationString());
            nm.setMethod("PUT");
            nm.doGet("");

            if ( nm.responseCode() == 200 ) {
                local viewUrl = "";

                try {
                    local t = ParseJSON(nm.responseBody());
                    href = t.href;
                    method = t.method;
                } catch ( ex ) {
                    href = regex_simple(data, "href\":\"(.+)\"", 0);
                    method = "GET";
                }
                nm.setMethod(method);
                nm.addQueryHeader("Authorization", _GetAuthorizationString());
                nm.doGet("https://cloud-api.yandex.net:443/v1/disk/resources?path=" + nm.urlEncode(remotePath));

                if (nm.responseCode() == 200) {
                    try {
                        local t = ParseJSON(nm.responseBody());
                        viewUrl = t.public_url;
                    } catch ( ex ) {
                        viewUrl = regex_simple(data, "public_url\":\"(.+)\"", 0);
                    }
                    options.setViewUrl(viewUrl);
                    return 1;
                }
            }
        }
        return 0;
    }

    try {
        while (_CheckIfExists(remotePathEncoded)) {
            local ext = GetFileExtension(ansiFileName);
            local suffix = i.tostring();
            if (i > 2) {
                suffix = md5(random().tostring()).slice(0, 4);
            }
            local filename = ansiFileName.slice(0,ansiFileName.len()-ext.len()-1) + "_" + suffix;

            if (ext.len()) {
                filename += "." + ext;
            }
            remotePathEncoded = folder + nm.urlEncode(filename);
            i++;
        }
        local url = "https://webdav.yandex.ru" + remotePathEncoded;
        nm.setUrl(url);
        nm.addQueryHeader("Authorization", _GetAuthorizationString());
        //nm.addQueryHeader("Expect", "100-continue");
        nm.addQueryHeader("Connection", "close");
        nm.addQueryHeader("Content-Type", "application/binary");
        nm.addQueryHeader("Content-Length", fileSize);
        nm.addQueryHeader("Transfer-Encoding", "");
        nm.setMethod("PUT");
        nm.doUpload(FileName, "");
        _CheckResponseCode();

        nm.setUrl(url);
        nm.setMethod("PROPPATCH");

        nm.addQueryHeader("Authorization", _GetAuthorizationString());
        nm.addQueryHeader("Content-Type", "application/xml");
        nm.addQueryHeader("Transfer-Encoding", "");
        local data = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
            "<propertyupdate xmlns=\"DAV:\">" +
            "<set>"+
            "<prop>" +
            "<public_url xmlns=\"urn:yandex:disk:meta\">true</public_url>" +
            "</prop>"  +
            "</set>"     +
            "</propertyupdate>";
        nm.doUpload("", data);
        _CheckResponseCode();
        local data = nm.responseBody();

        local viewUrl = regex_simple(data,"<public_url xmlns=\"urn:yandex:disk:meta\">(.+)</public_url>",0);

        options.setViewUrl(viewUrl);
    } catch ( ex ) {
        WriteLog("error", "Exception:" + ex.tostring());
        return 0;
    }

    return 1;
}

function GetFolderAccessTypeList() {
    return [
        tr("yandexdisk.privacy.private", "Private"),
		tr("yandexdisk.privacy.public", "Public"),
    ];
}

function GetServerParamList() {
    return {
        useWebdav = "Use WebDav",
        token = "Token",
        enableOAuth ="enableOAuth",
        tokenType = "tokenType",
        PrevLogin = "PrevLogin",
        OAuthLogin = "OAuthLogin"
    };
}