public class AuthManager {
    private boolean isAuthenticated = false;
    private String apiClientId;
    private CredentialsProvider credentialsProvider;

    public AuthManager(String apiClientId) {
        this.apiClientId = apiClientId;
        credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new DiadocCredentials(apiClientId, null));
    }

    public CredentialsProvider getCredentialsProvider() {
        return credentialsProvider;
    }

    public boolean isAuthenticated() {
        return isAuthenticated;
    }

    public void setCredentials(String authToken) {
        isAuthenticated = (authToken != null);
        credentialsProvider.setCredentials(AuthScope.ANY, new DiadocCredentials(apiClientId, authToken));
    }

    public void clearCredentials(){
        isAuthenticated = false;
        credentialsProvider.setCredentials(AuthScope.ANY, new DiadocCredentials(apiClientId, null));
    }
} public class AuthenticateClient {
    private static final String V_3_AUTHENTICATE = "/V3/Authenticate";
    private AuthManager authManager;
    private DiadocHttpClient diadocHttpClient;

    public AuthenticateClient(AuthManager authManager, DiadocHttpClient diadocHttpClient) {
        this.authManager = authManager;
        this.diadocHttpClient = diadocHttpClient;
    }

    public void authenticate(String sid) throws DiadocSdkException {
        try {
            authManager.clearCredentials();
            var request = RequestBuilder
                    .post(new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath(V_3_AUTHENTICATE)
                            .addParameter("type", "sid")
                            .build())
                    .addHeader("Content-Type", "text/plain")
                    .setEntity(new ByteArrayEntity(sid.getBytes()));

            var response = diadocHttpClient.performRequest(request);
            authManager.setCredentials(new String(response, UTF_8));
        } catch (URISyntaxException | IOException ex) {
            throw new DiadocSdkException(ex);
        }
    }

    public void authenticate(String login, String password) throws DiadocSdkException {
        try {
            authManager.clearCredentials();

            var request = RequestBuilder
                    .post(new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath(V_3_AUTHENTICATE)
                            .addParameter("type", "password")
                            .build())
                    .setEntity(new ByteArrayEntity(
                            LoginPasswordProtos.LoginPassword
                                    .newBuilder()
                                    .setLogin(login)
                                    .setPassword(password)
                                    .build()
                                    .toByteArray()));

            var response = diadocHttpClient.performRequest(request);
            authManager.setCredentials(new String(response, UTF_8));
        } catch (IOException | URISyntaxException e) {
            throw new DiadocSdkException(e);
        }

    }

    public void authenticate(X509Certificate currentCert, boolean autoConfirm) throws DiadocSdkException {
        try {
            authManager.clearCredentials();

            var request = RequestBuilder
                    .post(new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath(V_3_AUTHENTICATE)
                            .addParameter("type", "certificate")
                            .build())
                    .addHeader("Content-Type", "application/octet-stream")
                    .setEntity(new ByteArrayEntity(currentCert.getEncoded()));

            var response = diadocHttpClient.performRequest(request);

            if (autoConfirm) {
                String token = getDecryptedToken(response, currentCert);
                confirmAuthenticationByCertificate(currentCert, token);
            }
        } catch (URISyntaxException | IOException | CertificateEncodingException | TokenDecryptException ex) {
            throw new DiadocSdkException(ex);
        }
    }

    public void authenticate(X509Certificate currentCert) throws DiadocSdkException {
        authenticate(currentCert, true);
    }

    public void confirmAuthenticationByCertificate(X509Certificate currentCert, String token) throws DiadocSdkException {
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/V3/AuthenticateConfirm")
                            .addParameter("token", token)
                            .build())
                    .setEntity(new ByteArrayEntity(currentCert.getEncoded()));

            var response = diadocHttpClient.performRequest(request);

            authManager.setCredentials(StringUtils.newStringUtf8(response));
        } catch (URISyntaxException | CertificateEncodingException | IOException ex) {
            throw new DiadocSdkException(ex);
        }
    }

    private String getDecryptedToken(byte[] encryptedToken, X509Certificate currentCert) throws TokenDecryptException {
        return StringUtils.newStringUtf8(Base64.encodeBase64(TokenDecryptManager.decryptToken(encryptedToken, currentCert)));
    }

    public ExternalServiceAuthInfo getExternalServiceAuthInfo(String key) throws DiadocSdkException {
        if (key == null) {
            throw new IllegalArgumentException("key");
        }
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetExternalServiceAuthInfo")
                            .addParameter("key", key)
                            .build());
            var response = diadocHttpClient.performRequest(request);
            return ExternalServiceAuthInfo.parseFrom(response);
        } catch (URISyntaxException | IOException ex) {
            throw new DiadocSdkException(ex);
        }
    }
} public class CounteragentClient {
    private DiadocHttpClient diadocHttpClient;

    public CounteragentClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public AsyncMethodResult acquireCounteragent(String myOrgId, AcquireCounteragentRequest acquireCounteragentRequest) throws DiadocSdkException {
        return acquireCounteragent(myOrgId, null, acquireCounteragentRequest);
    }

    public AsyncMethodResult acquireCounteragent(
            String myOrgId,
            @Nullable String myDepartmentId,
            AcquireCounteragentRequest acquireCounteragentRequest) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(myOrgId)) {
            throw new IllegalArgumentException("myOrgId");
        }

        if (acquireCounteragentRequest == null) {
            throw new IllegalArgumentException("acquireCounteragentRequest");
        }

        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/V2/AcquireCounteragent")
                    .addParameter("myOrgId", myOrgId);

            if (myDepartmentId != null) {
                url.addParameter("myDepartmentId", myDepartmentId);
            }

            var request = RequestBuilder
                    .post(url.build())
                    .setEntity(new ByteArrayEntity(acquireCounteragentRequest.toByteArray()));

            return AsyncMethodResult.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public AcquireCounteragentResult waitAcquireCounteragentResult(String taskId, Integer timeoutInMillis) throws DiadocSdkException, DiadocException {
        try {
            byte[] data = diadocHttpClient.waitTaskResult("/AcquireCounteragentResult", taskId, timeoutInMillis);
            return AcquireCounteragentResult.parseFrom(data);
        } catch (IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Counteragent getCounteragent(String myOrgId, String counteragentOrgId) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(myOrgId)) {
            throw new IllegalArgumentException("myOrgId");
        }
        if (Tools.isNullOrEmpty(counteragentOrgId)) {
            throw new IllegalArgumentException("counteragentOrgId");
        }

        try {
            var request = RequestBuilder
                    .get(new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/V2/GetCounteragent")
                            .addParameter("myOrgId", myOrgId)
                            .addParameter("counteragentOrgId", counteragentOrgId)
                            .build());
            return Counteragent.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public CounteragentCertificateList getCounteragentCertificates(String myOrgId, String counteragentOrgId) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(myOrgId)) {
            throw new IllegalArgumentException("myOrgId");
        }
        if (Tools.isNullOrEmpty(counteragentOrgId)) {
            throw new IllegalArgumentException("counteragentOrgId");
        }

        try {
            var request = RequestBuilder
                    .get(new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetCounteragentCertificates")
                            .addParameter("myOrgId", myOrgId)
                            .addParameter("counteragentOrgId", counteragentOrgId)
                            .build());
            return CounteragentCertificateList.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public CounteragentList getCounteragents(String myOrgId, @Nullable String counteragentStatus, @Nullable String afterIndexKey) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(myOrgId)) {
            throw new IllegalArgumentException("myOrgId");
        }
        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/V2/GetCounteragents")
                    .addParameter("myOrgId", myOrgId);

            if (!Tools.isNullOrEmpty(counteragentStatus)) {
                url.addParameter("counteragentStatus", counteragentStatus);
            }

            if (afterIndexKey != null) {
                url.addParameter("afterIndexKey", afterIndexKey);
            }

            var request = RequestBuilder.get(url.build());
            return CounteragentList.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public void breakWithCounteragent(String myOrgId, String counteragentOrgId, @Nullable String comment) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(myOrgId)) {
            throw new IllegalArgumentException("myOrgId");
        }
        if (Tools.isNullOrEmpty(counteragentOrgId)) {
            throw new IllegalArgumentException("counteragentOrgId");
        }

        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/BreakWithCounteragent")
                    .addParameter("myOrgId", myOrgId)
                    .addParameter("counteragentOrgId", counteragentOrgId);

            if (!Tools.isNullOrEmpty(comment)) {
                url.addParameter("comment", comment);
            }

            var request = RequestBuilder.post(url.build());
            diadocHttpClient.performRequest(request);
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }
} public class DepartmentClient {
    private DiadocHttpClient diadocHttpClient;

    public DepartmentClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public Department createDepartment(String boxId, DepartmentToCreate departmentToCreate) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }

        if (departmentToCreate == null) {
            throw new IllegalArgumentException("departmentToCreate");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/admin/CreateDepartment")
                            .addParameter("boxId", boxId)
                            .build())
                    .setEntity(new ByteArrayEntity(departmentToCreate.toByteArray()));
            return Department.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Department updateDepartment(String boxId, String departmentId, DepartmentToUpdate departmentToUpdate) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (departmentId == null) {
            throw new IllegalArgumentException("departmentId");
        }
        if (departmentToUpdate == null) {
            throw new IllegalArgumentException("departmentToUpdate");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/admin/UpdateDepartment")
                            .addParameter("boxId", boxId)
                            .addParameter("departmentId", departmentId)
                            .build())
                    .setEntity(new ByteArrayEntity(departmentToUpdate.toByteArray()));
            return Department.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public void deleteDepartment(String boxId, String departmentId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (departmentId == null) {
            throw new IllegalArgumentException("departmentId");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/admin/DeleteDepartment")
                            .addParameter("boxId", boxId)
                            .addParameter("departmentId", departmentId)
                            .build());
            diadocHttpClient.performRequest(request);
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Department getDepartmentByFullId(String boxId, String departmentId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (departmentId == null) {
            throw new IllegalArgumentException("departmentId");
        }

        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/admin/GetDepartment")
                            .addParameter("boxId", boxId)
                            .addParameter("departmentId", departmentId)
                            .build());
            return Department.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public DepartmentList getDepartments(String boxId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        return getDepartments(boxId, null, null);
    }

    public DepartmentList getDepartments(String boxId, int page) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        return getDepartments(boxId, page, null);
    }

    public DepartmentList getDepartments(String boxId, @Nullable Integer page, @Nullable Integer count) throws DiadocSdkException {
        if(boxId == null) {
            throw new IllegalArgumentException("boxId");
        }

        if(page != null && page < 1) {
            throw new IllegalArgumentException("page must be 1 or greater");
        }

        if(count != null && count < 1) {
            throw new IllegalArgumentException("count must be 1 or greater");
        }

        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/admin/GetDepartments")
                    .addParameter("boxId", boxId);

            if (page != null) {
                url.addParameter("page", Integer.toString(page));
            }

            if (count != null) {
                url.addParameter("count", Integer.toString(count));
            }

            var request = RequestBuilder.get(url.build());
            return DepartmentList.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public OrganizationProtos.Department getDepartment(String orgId, String departmentId) throws DiadocSdkException {
        if (orgId == null) {
            throw new IllegalArgumentException("orgId");
        }
        if (departmentId == null) {
            throw new IllegalArgumentException("departmentId");
        }
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetDepartment")
                            .addParameter("orgId", orgId)
                            .addParameter("departmentId", departmentId)
                            .build());
            return OrganizationProtos.Department.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }
} public class DocflowClient {
    private DiadocHttpClient diadocHttpClient;

    public DocflowClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public SearchDocflowsResponse searchDocflows(String boxId, SearchDocflowsRequest searchDocflowsRequest) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/SearchDocflows")
                            .addParameter("boxId", boxId)
                            .build())
                    .setEntity(new ByteArrayEntity(searchDocflowsRequest.toByteArray()));
            return SearchDocflowsResponse.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GetDocflowsByPacketIdResponse getDocflowsByPacketId(String boxId, GetDocflowsByPacketIdRequest packetIdRequest) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/V2/GetDocflowsByPacketId")
                            .addParameter("boxId", boxId)
                            .build())
                    .setEntity(new ByteArrayEntity(packetIdRequest.toByteArray()));
            return GetDocflowsByPacketIdResponse.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GetDocflowBatchResponseV3 getDocflows(String boxId, GetDocflowBatchRequest getDocflowBatchRequest) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/V3/GetDocflows")
                            .addParameter("boxId", boxId)
                            .build())
                    .setEntity(new ByteArrayEntity(getDocflowBatchRequest.toByteArray()));
            return GetDocflowBatchResponseV3.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GetDocflowEventsResponseV3 getDocflowEvents(String boxId, GetDocflowEventsRequest getDocflowEventsRequest) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/V3/GetDocflowEvents")
                            .addParameter("boxId", boxId)
                            .build())
                    .setEntity(new ByteArrayEntity(getDocflowEventsRequest.toByteArray()));
            return GetDocflowEventsResponseV3.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public SearchDocflowsResponseV3 searchDocflowsV3(String boxId, SearchDocflowsRequest docflowsRequest) throws IOException, DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/V3/SearchDocflows")
                            .addParameter("boxId", boxId)
                            .build())
                    .setEntity(new ByteArrayEntity(docflowsRequest.toByteArray()));
            return SearchDocflowsResponseV3.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GetDocflowsByPacketIdResponseV3 getDocflowsByPacketIdV3(String boxId, GetDocflowsByPacketIdRequest docflowsByPacketIdRequest) throws IOException, DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/V3/GetDocflowsByPacketId")
                            .addParameter("boxId", boxId)
                            .build())
                    .setEntity(new ByteArrayEntity(docflowsByPacketIdRequest.toByteArray()));
            return GetDocflowsByPacketIdResponseV3.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }
} public class DocumentClient {
    private DiadocHttpClient diadocHttpClient;

    public DocumentClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public DocumentList getDocuments(DocumentsFilter filter) throws DiadocSdkException {
        if (filter.getBoxId() == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (filter.getFilterCategory() == null) {
            throw new IllegalArgumentException("filterCategory");
        }

        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/V3/GetDocuments")
                    .addParameter("boxId", filter.getBoxId())
                    .addParameter("filterCategory", filter.getFilterCategory());

            if (!Tools.isNullOrEmpty(filter.getCounteragentBoxId())) {
                url.addParameter("counteragentBoxId", filter.getCounteragentBoxId());
            }

            if (filter.getTimestampFrom() != null) {
                var fromTicks = Tools.toCsTicks(filter.getTimestampFrom().getTime());
                url.addParameter("timestampFromTicks", Long.toString(fromTicks));
            }

            if (filter.getTimestampTo() != null) {
                var toTicks = Tools.toCsTicks(filter.getTimestampTo().getTime());
                url.addParameter("timestampToTicks", Long.toString(toTicks));
            }

            if (!Tools.isNullOrEmpty(filter.getFromDocumentDate())) {
                url.addParameter("fromDocumentDate", filter.getFromDocumentDate());
            }

            if (!Tools.isNullOrEmpty(filter.getToDocumentDate())) {
                url.addParameter("toDocumentDate", filter.getToDocumentDate());
            }
            if (!Tools.isNullOrEmpty(filter.getDepartmentId())) {
                url.addParameter("departmentId", filter.getDepartmentId());
            }

            if (filter.isExcludeSubdepartments()) {
                url.addParameter("excludeSubdepartments", null);
            }

            if (!Tools.isNullOrEmpty(filter.getSortDirection())) {
                url.addParameter("sortDirection", filter.getSortDirection());
            }

            if (filter.getAfterIndexKey() != null) {
                url.addParameter("afterIndexKey", filter.getAfterIndexKey());
            }
            if (filter.getCount() != null) {
                url.addParameter("count", filter.getCount().toString());
            }

            var request = RequestBuilder.get(url.build());

            return DocumentList.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public DocumentList getDocuments(
            String boxId,
            String filterCategory,
            String counteragentBoxId,
            Date timestampFrom,
            Date timestampTo,
            String fromDocumentDate,
            String toDocumentDate,
            String departmentId,
            boolean excludeSubdepartments,
            String afterIndexKey,
            Integer count) throws DiadocSdkException {
        return getDocuments(new DocumentsFilter()
                .setBoxId(boxId)
                .setFilterCategory(filterCategory)
                .setCounteragentBoxId(counteragentBoxId)
                .setTimestampFrom(timestampFrom)
                .setTimestampTo(timestampTo)
                .setFromDocumentDate(fromDocumentDate)
                .setToDocumentDate(toDocumentDate)
                .setDepartmentId(departmentId)
                .setExcludeSubdepartments(excludeSubdepartments)
                .setAfterIndexKey(afterIndexKey)
                .setCount(count));
    }

    public DocumentList getDocuments(String boxId,
                                     String filterCategory,
                                     String counteragentBoxId,
                                     Date timestampFrom,
                                     Date timestampTo,
                                     String fromDocumentDate,
                                     String toDocumentDate,
                                     String departmentId,
                                     boolean excludeSubdepartments,
                                     String afterIndexKey) throws DiadocSdkException {
        return getDocuments(
                boxId,
                filterCategory,
                counteragentBoxId,
                timestampFrom,
                timestampTo,
                fromDocumentDate,
                toDocumentDate,
                departmentId,
                excludeSubdepartments,
                afterIndexKey,
                null);
    }

    public Document getDocument(String boxId, String messageId, String entityId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (messageId == null) {
            throw new IllegalArgumentException("messageId");
        }
        if (entityId == null) {
            throw new IllegalArgumentException("entityId");
        }

        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/V3/GetDocument")
                            .addParameter("boxId", boxId)
                            .addParameter("messageId", messageId)
                            .addParameter("entityId", entityId)
                            .build());
            return Document.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public void moveDocuments(DocumentsMoveOperation operation) throws DiadocSdkException {
        if (operation == null) {
            throw new IllegalArgumentException("operation");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/MoveDocuments")
                            .build())
                    .setEntity(new ByteArrayEntity(operation.toByteArray()));
            diadocHttpClient.performRequest(request);
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public DocumentList getDocumentsByMessageId(String boxId, String messageId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (messageId == null) {
            throw new IllegalArgumentException("messageId");
        }
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetDocumentsByMessageId")
                            .addParameter("boxId", boxId)
                            .addParameter("messageId", messageId)
                            .build());
            return DocumentList.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public PrepareDocumentsToSignResponse prepareDocumentsToSign(PrepareDocumentsToSignRequest documentsToSignRequest) throws DiadocSdkException {
        if (documentsToSignRequest == null) {
            throw new IllegalArgumentException("documentsToSignRequest");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/PrepareDocumentsToSign")
                            .build())
                    .setEntity(new ByteArrayEntity(documentsToSignRequest.toByteArray()));
            return PrepareDocumentsToSignResponse.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public byte[] getEntityContent(String currentBoxId, String messageId, String entityId) throws IOException, DiadocSdkException {
        if (currentBoxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (messageId == null) {
            throw new IllegalArgumentException("messageId");
        }
        if (entityId == null) {
            throw new IllegalArgumentException("entityId");
        }
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/V4/GetEntityContent")
                            .addParameter("boxId", currentBoxId)
                            .addParameter("messageId", messageId)
                            .addParameter("entityId", entityId)
                            .build());
            return diadocHttpClient.performRequest(request);
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public SignatureInfo getSignatureInfo(String boxId, String messageId, String entityId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (messageId == null) {
            throw new IllegalArgumentException("messageId");
        }
        if (entityId == null) {
            throw new IllegalArgumentException("entityId");
        }

        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetSignatureInfo")
                            .addParameter("boxId", boxId)
                            .addParameter("messageId", messageId)
                            .addParameter("entityId", entityId)
                            .build());
            return SignatureInfo.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }


} public class DocumentTypeClient {
    public DiadocHttpClient diadocHttpClient;

    public DocumentTypeClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public GetDocumentTypesResponseV2 getDocumentTypesV2(String boxId) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/V2/GetDocumentTypes")
                            .addParameter("boxId", boxId)
                            .build());
            return GetDocumentTypesResponseV2.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public DetectDocumentTypesResponse detectDocumentTypes(String boxId, String nameOnShelf) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        if (Tools.isNullOrEmpty(nameOnShelf)) {
            throw new IllegalArgumentException("nameOnShelf");
        }

        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/DetectDocumentTypes")
                            .addParameter("boxId", boxId)
                            .addParameter("nameOnShelf", nameOnShelf)
                            .build());
            return DetectDocumentTypesResponse.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }

    }

    public DetectDocumentTypesResponse detectDocumentTypes(String boxId, byte[] content) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/DetectDocumentTypes")
                            .addParameter("boxId", boxId)
                            .build())
                    .setEntity(new ByteArrayEntity(content));
            return DetectDocumentTypesResponse.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public FileContent getContent(String typeNamedId, String function, String version, int titleIndex, XsdContentType contentType) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(typeNamedId)) {
            throw new IllegalArgumentException("typeNamedId");
        }
        if (Tools.isNullOrEmpty(function)) {
            throw new IllegalArgumentException("function");
        }
        if (Tools.isNullOrEmpty(version)) {
            throw new IllegalArgumentException("version");
        }
        if (titleIndex < 0) {
            throw new IllegalArgumentException("titleIndex should be non-negative");
        }
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetContent")
                            .addParameter("typeNamedId", typeNamedId)
                            .addParameter("function", function)
                            .addParameter("version", version)
                            .addParameter("titleIndex", Integer.toString(titleIndex))
                            .addParameter("contentType", contentType.name())
                            .build());
            return diadocHttpClient.performRequestWithFileContent(request);
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public FileContent getContent(String typeNamedId, String function, String version, int titleIndex) throws DiadocSdkException {
        return getContent(typeNamedId, function, version, titleIndex, XsdContentType.TitleXsd);
    }

    public DetectTitleResponse detectDocumentTitles(String boxId, String nameOnShelf) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        if (Tools.isNullOrEmpty(nameOnShelf)) {
            throw new IllegalArgumentException("nameOnShelf");
        }

        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/DetectDocumentTitles")
                            .addParameter("boxId", boxId)
                            .addParameter("nameOnShelf", nameOnShelf)
                            .build());
            return DetectTitleResponse.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public DetectTitleResponse detectDocumentTitles(String boxId, byte[] content) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/DetectDocumentTitles")
                            .addParameter("boxId", boxId)
                            .build())
                    .setEntity(new ByteArrayEntity(content));
            return DetectTitleResponse.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }
} public class EmployeeClient {
    private DiadocHttpClient diadocHttpClient;

    public EmployeeClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public Employee createEmployee(String boxId, EmployeeToCreate employeeToCreate) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }

        if (employeeToCreate == null) {
            throw new IllegalArgumentException("employeeToCreate");
        }
        try {

            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/CreateEmployee")
                            .addParameter("boxId", boxId)
                            .build())
                    .setEntity(new ByteArrayEntity(employeeToCreate.toByteArray()));

            return Employee.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Employee updateEmployee(String boxId, String userId, EmployeeToUpdate employeeToUpdate) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (userId == null) {
            throw new IllegalArgumentException("userId");
        }
        if (employeeToUpdate == null) {
            throw new IllegalArgumentException("employeeToUpdate");
        }

        try {

            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/UpdateEmployee")
                            .addParameter("boxId", boxId)
                            .addParameter("userId", userId)
                            .build())
                    .setEntity(new ByteArrayEntity(employeeToUpdate.toByteArray()));

            return Employee.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public void deleteEmployee(String boxId, String userId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (userId == null) {
            throw new IllegalArgumentException("userId");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/DeleteEmployee")
                            .addParameter("boxId", boxId)
                            .addParameter("userId", userId)
                            .build())
                    .addHeader("Content-Length", "0" );

            diadocHttpClient.performRequest(request);
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public EmployeeList getEmployees(String boxId, @Nullable Integer page, @Nullable Integer count) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (page != null && page < 1) {
            throw new IllegalArgumentException("page must be 1 or greater");
        }
        if (count != null && count < 1) {
            throw new IllegalArgumentException("count must be 1 or greater");
        }

        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/GetEmployees")
                    .addParameter("boxId", boxId);

            if (page != null) {
                url.addParameter("page", Integer.toString(page));
            }

            if (count != null) {
                url.addParameter("count", Integer.toString(count));
            }

            var request = RequestBuilder.get(url.build());
            return EmployeeList.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public EmployeeList getEmployees(String boxId) throws DiadocSdkException {
        return getEmployees(boxId, null, null);
    }

    public EmployeeList getEmployees(String boxId, int page) throws DiadocSdkException {
        return getEmployees(boxId, page, null);
    }

    public Employee getEmployee(String boxId, String userId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (userId == null) {
            throw new IllegalArgumentException("userId");
        }

        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetEmployee")
                            .addParameter("boxId", boxId)
                            .addParameter("userId", userId)
                            .build());
            return Employee.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Employee getMyEmployee(String boxId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetMyEmployee")
                            .addParameter("boxId", boxId)
                            .build());
            return Employee.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public EmployeeSubscriptions getSubscriptions(String boxId, String userId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (userId == null) {
            throw new IllegalArgumentException("userId");
        }

        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetSubscriptions")
                            .addParameter("boxId", boxId)
                            .addParameter("userId", userId)
                            .build());
            return EmployeeSubscriptions.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public CertificateList getMyCertificates(String boxId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetMyCertificates")
                            .addParameter("boxId", boxId)
                            .build());
            return CertificateList.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public EmployeeSubscriptions updateSubscriptions(String boxId, String userId, SubscriptionsToUpdate subscriptionsToUpdate) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (userId == null) {
            throw new IllegalArgumentException("userId");
        }
        if(subscriptionsToUpdate == null) {
            throw new IllegalArgumentException("subscriptionsToUpdate");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/UpdateSubscriptions")
                            .addParameter("boxId", boxId)
                            .addParameter("userId", userId)
                            .build())
                    .setEntity(new ByteArrayEntity(subscriptionsToUpdate.toByteArray()));

            return EmployeeSubscriptions.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }
} public class EventsClient {
    private DiadocHttpClient diadocHttpClient;

    public EventsClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public BoxEventList getNewEvents(String currentBoxId, @Nullable String eventIdCurrent) throws DiadocSdkException {
        if (currentBoxId == null) {
            throw new IllegalArgumentException("currentBoxId");
        }

        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/V6/GetNewEvents")
                    .addParameter("boxId", currentBoxId)
                    .addParameter("includeDrafts", null);

            if (eventIdCurrent != null) {
                url.addParameter("afterEventId", eventIdCurrent);
            }

            var request = RequestBuilder.get(url.build());
            return BoxEventList.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    @Nullable
    public BoxEvent getLastEvent(String boxId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }

        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetLastEvent")
                            .addParameter("boxId", boxId).build());
            var response = diadocHttpClient.getRawResponse(request);
            if(response.getStatusCode() == HttpStatus.SC_NO_CONTENT){
                return null;
            }
            return BoxEvent.parseFrom(response.getContent());
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public BoxEvent getEvent(String boxId, String eventId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (eventId == null) {
            throw new IllegalArgumentException("eventId");
        }
        try {

            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/V2/GetEvent")
                            .addParameter("boxId", boxId)
                            .addParameter("eventId", eventId)
                            .build());
            return BoxEvent.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

} public class GenerateClient {
    private DiadocHttpClient diadocHttpClient;

    public GenerateClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public GeneratedFile generateInvoiceCorrectionRequestXml(String boxId,
                                                             String messageId,
                                                             String attachmentId,
                                                             InvoiceCorrectionRequestInfo invoiceCorrectionInfo) throws DiadocSdkException {
        return getGeneratedXml(boxId, messageId, attachmentId, "/GenerateInvoiceCorrectionRequestXml", invoiceCorrectionInfo);
    }
    public GeneratedFile generateRevocationRequestXml(String boxId,
                                                      String messageId,
                                                      String attachmentId,
                                                      RevocationRequestInfo revocationRequestInfo) throws DiadocSdkException {
        return generateRevocationRequestXml(boxId, messageId, attachmentId, revocationRequestInfo, null);
    }

    public GeneratedFile generateRevocationRequestXml(String boxId,
                                                      String messageId,
                                                      String attachmentId,
                                                      RevocationRequestInfo revocationRequestInfo,
                                                      @Nullable String contentTypeId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (messageId == null) {
            throw new IllegalArgumentException("messageId");
        }
        if (attachmentId == null) {
            throw new IllegalArgumentException("attachmentId");
        }

        try {
            var uriBuilder = new URIBuilder(diadocHttpClient.getBaseUrl())
                .setPath("/V2/GenerateRevocationRequestXml")
                .addParameter("boxId", boxId)
                .addParameter("messageId", messageId)
                .addParameter("attachmentId", attachmentId);
            if(contentTypeId != null) {
                uriBuilder.addParameter("contentTypeId", contentTypeId);
            }
            var request = RequestBuilder.post(uriBuilder.build())
                    .setEntity(new ByteArrayEntity(revocationRequestInfo.toByteArray()));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateSignatureRejectionXml(String boxId,
                                                       String messageId,
                                                       String attachmentId,
                                                       SignatureRejectionInfo signatureRejectionInfo) throws DiadocSdkException {
        return getGeneratedXml(boxId, messageId, attachmentId, "/GenerateSignatureRejectionXml", signatureRejectionInfo);
    }

    public GeneratedFile generateReceiptXml(String boxId, String messageId, String attachmentId, Signer signer) throws DiadocSdkException {
        return getGeneratedXml(boxId, messageId, attachmentId, "/GenerateReceiptXml", signer);
    }

    private <T extends GeneratedMessage> GeneratedFile getGeneratedXml(
            String boxId,
            String messageId,
            String attachmentId,
            String path,
            T data) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (messageId == null) {
            throw new IllegalArgumentException("messageId");
        }
        if (attachmentId == null) {
            throw new IllegalArgumentException("attachmentId");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath(path)
                            .addParameter("boxId", boxId)
                            .addParameter("messageId", messageId)
                            .addParameter("attachmentId", attachmentId)
                            .build())
                    .setEntity(new ByteArrayEntity(data.toByteArray()));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateInvoiceXml(InvoiceInfo invoiceInfo) throws DiadocSdkException {
        return generateInvoiceXml(invoiceInfo, "Invoice", false);
    }

    public GeneratedFile generateInvoiceXml(InvoiceInfo invoiceInfo, boolean disableValidation) throws DiadocSdkException {
        return generateInvoiceXml(invoiceInfo, "Invoice", disableValidation);
    }

    public GeneratedFile generateInvoiceRevisionXml(InvoiceInfo invoiceRevisionInfo) throws DiadocSdkException {
        return generateInvoiceXml(invoiceRevisionInfo, "InvoiceRevision", false);
    }

    public GeneratedFile generateInvoiceRevisionXml(InvoiceInfo invoiceRevisionInfo, boolean disableValidation) throws DiadocSdkException {
        return generateInvoiceXml(invoiceRevisionInfo, "InvoiceRevision", disableValidation);
    }

    public GeneratedFile generateInvoiceCorrectionXml(InvoiceCorrectionInfo invoiceCorrectionInfo) throws DiadocSdkException {
        return generateInvoiceXml(invoiceCorrectionInfo, "InvoiceCorrection", false);
    }

    public GeneratedFile generateInvoiceCorrectionXml(InvoiceCorrectionInfo invoiceCorrectionInfo, boolean disableValidation) throws DiadocSdkException {
        return generateInvoiceXml(invoiceCorrectionInfo, "InvoiceCorrection", disableValidation);
    }

    public GeneratedFile generateInvoiceCorrectionRevisionXml(InvoiceCorrectionInfo invoiceCorrectionRevisionInfo) throws DiadocSdkException {
        return generateInvoiceXml(invoiceCorrectionRevisionInfo, "InvoiceCorrectionRevision", false);
    }

    public GeneratedFile generateInvoiceCorrectionRevisionXml(InvoiceCorrectionInfo invoiceCorrectionRevisionInfo, boolean disableValidation) throws DiadocSdkException {
        return generateInvoiceXml(invoiceCorrectionRevisionInfo, "InvoiceCorrectionRevision", disableValidation);
    }

    private GeneratedFile generateInvoiceXml(MessageLite invoiceInfo, String invoiceType, boolean disableValidation) throws DiadocSdkException {
        if (invoiceInfo == null) {
            throw new IllegalArgumentException("info");
        }
        try {

            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GenerateInvoiceXml")
                            .addParameter("invoiceType", invoiceType)
                            .addParameter("disableValidation", String.valueOf(disableValidation)).build())
                    .setEntity(new ByteArrayEntity(invoiceInfo.toByteArray()));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateTitleXml(
            String boxId,
            String documentTypeNamedId,
            String documentFunction,
            String documentVersion,
            Integer titleIndex,
            byte[] userContractData,
            @Nullable String editingSettingId,
            boolean disableValidation,
            @Nullable String letterId,
            @Nullable String documentId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (documentTypeNamedId == null) {
            throw new IllegalArgumentException("documentTypeNamedId");
        }
        if (documentFunction == null) {
            throw new IllegalArgumentException("documentFunction");
        }
        if (documentVersion == null) {
            throw new IllegalArgumentException("documentVersion");
        }
        if (userContractData == null) {
            throw new IllegalArgumentException("userContractData");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GenerateTitleXml")
                            .addParameter("boxId", boxId)
                            .addParameter("documentTypeNamedId", documentTypeNamedId)
                            .addParameter("documentFunction", documentFunction)
                            .addParameter("documentVersion", documentVersion)
                            .addParameter("titleIndex", titleIndex.toString())
                            .addParameter("disableValidation", Boolean.toString(disableValidation))
                            .addParameter("editingSettingId", editingSettingId)
                            .addParameter("letterId", letterId)
                            .addParameter("documentId", documentId).build())
                    .setEntity(new ByteArrayEntity(userContractData));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateTitleXml(
            String boxId,
            String documentTypeNamedId,
            String documentFunction,
            String documentVersion,
            Integer titleIndex,
            byte[] userContractData,
            String editingSettingId,
            boolean disableValidation) throws DiadocSdkException {
        return generateTitleXml(
                boxId,
                documentTypeNamedId,
                documentFunction,
                documentVersion,
                titleIndex,
                userContractData,
                editingSettingId,
                disableValidation,
                null,
                null);
    }

    public GeneratedFile generateTitleXml(
            String boxId,
            String documentTypeNamedId,
            String documentFunction,
            String documentVersion,
            Integer titleIndex,
            byte[] userContractData,
            String letterId,
            String documentId) throws DiadocSdkException {
        return generateTitleXml(
                boxId,
                documentTypeNamedId,
                documentFunction,
                documentVersion,
                titleIndex,
                userContractData,
                null,
                false,
                letterId,
                documentId);
    }

    public GeneratedFile generateSenderTitleXml(
            String boxId,
            String documentTypeNamedId,
            String documentFunction,
            String documentVersion,
            byte[] userContractData,
            @Nullable String editingSettingId,
            boolean disableValidation) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (documentTypeNamedId == null) {
            throw new IllegalArgumentException("documentTypeNamedId");
        }
        if (documentFunction == null) {
            throw new IllegalArgumentException("documentFunction");
        }
        if (documentVersion == null) {
            throw new IllegalArgumentException("documentVersion");
        }
        if (userContractData == null) {
            throw new IllegalArgumentException("userContractData");
        }

        try {

            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GenerateSenderTitleXml")
                            .addParameter("boxId", boxId)
                            .addParameter("documentTypeNamedId", documentTypeNamedId)
                            .addParameter("documentFunction", documentFunction)
                            .addParameter("documentVersion", documentVersion)
                            .addParameter("disableValidation", Boolean.toString(disableValidation))
                            .addParameter("editingSettingId", editingSettingId).build())
                    .setEntity(new ByteArrayEntity(userContractData));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateSenderTitleXml(
            String boxId,
            String documentTypeNamedId,
            String documentFunction,
            String documentVersion,
            byte[] userContractData) throws DiadocSdkException {
        return generateSenderTitleXml(
                boxId,
                documentTypeNamedId,
                documentFunction,
                documentVersion,
                userContractData,
                null,
                false);
    }

    public GeneratedFile generateRecipientTitleXml(
            String boxId,
            String senderTitleMessageId,
            String senderTitleAttachmentId,
            byte[] userContractData,
            @Nullable String documentVersion
    ) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (senderTitleMessageId == null) {
            throw new IllegalArgumentException("senderTitleMessageId");
        }
        if (senderTitleAttachmentId == null) {
            throw new IllegalArgumentException("senderTitleAttachmentId");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GenerateRecipientTitleXml")
                            .addParameter("boxId", boxId)
                            .addParameter("senderTitleMessageId", senderTitleMessageId)
                            .addParameter("senderTitleAttachmentId", senderTitleAttachmentId)
                            .addParameter("documentVersion", documentVersion).build())
                    .setEntity(new ByteArrayEntity(userContractData));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateRecipientTitleXml(
            String boxId,
            String senderTitleMessageId,
            String senderTitleAttachmentId,
            byte[] userContractData
    ) throws DiadocSdkException {
        return generateRecipientTitleXml(boxId, senderTitleMessageId, senderTitleAttachmentId, userContractData, null);
    }

    private <T extends GeneratedMessage> GeneratedFile generateTorgXmlForSeller(
            T sellerTitleInfo,
            boolean disableValidation,
            @Nullable String documentVersion) throws DiadocSdkException {
        if (sellerTitleInfo == null) {
            throw new IllegalArgumentException("sellerTitleInfo");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GenerateTorg12XmlForSeller")
                            .addParameter("disableValidation", String.valueOf(disableValidation))
                            .addParameter("documentVersion", documentVersion)
                            .build())
                    .setEntity(new ByteArrayEntity(sellerTitleInfo.toByteArray()));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateTorg12XmlForSeller(Torg12SellerTitleInfo sellerTitleInfo) throws DiadocSdkException {
        return generateTorgXmlForSeller(sellerTitleInfo, false, null);
    }

    public GeneratedFile generateTorg12XmlForSeller(Torg12SellerTitleInfo sellerTitleInfo, boolean disableValidation) throws DiadocSdkException {
        return generateTorgXmlForSeller(sellerTitleInfo, disableValidation, null);
    }

    public GeneratedFile generateTovTorg551XmlForSeller(TovTorgSellerTitleInfo sellerTitleInfo, boolean disableValidation) throws DiadocSdkException {
        return generateTorgXmlForSeller(sellerTitleInfo, disableValidation, "tovtorg_05_01_04");
    }

    public GeneratedFile generateTovTorg551XmlForSeller(TovTorgInfoProtos.TovTorgSellerTitleInfo sellerTitleInfo) throws DiadocSdkException {
        return generateTovTorg551XmlForSeller(sellerTitleInfo, false);
    }

    public GeneratedFile generateTorg12XmlForBuyer(
            Torg12BuyerTitleInfo buyerTitleInfo,
            String boxId,
            String sellerTitleMessageId,
            String sellerTitleAttachmentId) throws DiadocSdkException {
        return generateTorgXmlForBuyer(buyerTitleInfo, boxId, sellerTitleMessageId, sellerTitleAttachmentId, null);
    }

    public GeneratedFile generateTovTorg551XmlForBuyer(
            TovTorgInfoProtos.TovTorgBuyerTitleInfo buyerTitleInfo,
            String boxId,
            String sellerTitleMessageId,
            String sellerTitleAttachmentId,
            String documentVersion) throws DiadocSdkException {

        if (documentVersion == null) {
            throw new IllegalArgumentException("documentVersion");
        }
        return generateTorgXmlForBuyer(buyerTitleInfo, boxId, sellerTitleMessageId, sellerTitleAttachmentId, documentVersion);
    }

    public GeneratedFile generateTovTorg551XmlForBuyer(
            TovTorgInfoProtos.TovTorgBuyerTitleInfo buyerTitleInfo,
            String boxId,
            String sellerTitleMessageId,
            String sellerTitleAttachmentId) throws DiadocSdkException {
        return generateTovTorg551XmlForBuyer(buyerTitleInfo, boxId, sellerTitleMessageId, sellerTitleAttachmentId, "tovtorg_05_01_04");
    }

    private <T extends GeneratedMessage> GeneratedFile generateTorgXmlForBuyer(
            T buyerTitleInfo,
            String boxId,
            String sellerTitleMessageId,
            String sellerTitleAttachmentId,
            @Nullable String documentVersion) throws DiadocSdkException {
        if (buyerTitleInfo == null) {
            throw new IllegalArgumentException("buyerTitleInfo");
        }
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (sellerTitleMessageId == null) {
            throw new IllegalArgumentException("sellerTitleMessageId");
        }
        if (sellerTitleAttachmentId == null) {
            throw new IllegalArgumentException("sellerTitleAttachmentId");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GenerateTorg12XmlForBuyer")
                            .addParameter("boxId", boxId)
                            .addParameter("sellerTitleMessageId", sellerTitleMessageId)
                            .addParameter("sellerTitleAttachmentId", sellerTitleAttachmentId)
                            .addParameter("documentVersion", documentVersion)
                            .build())
                    .setEntity(new ByteArrayEntity(buyerTitleInfo.toByteArray()));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateAcceptanceCertificateXmlForSeller(AcceptanceCertificateSellerTitleInfo sellerTitleInfo) throws DiadocSdkException {
        return generateAcceptanceCertificateXmlForSeller(sellerTitleInfo, false, null);
    }

    public GeneratedFile generateAcceptanceCertificateXmlForSeller(AcceptanceCertificateSellerTitleInfo sellerTitleInfo, boolean disableValidation) throws DiadocSdkException {
        return generateAcceptanceCertificateXmlForSeller(sellerTitleInfo, disableValidation, null);
    }

    public GeneratedFile generateAcceptanceCertificate552XmlForSeller(AcceptanceCertificate552SellerTitleInfo sellerTitleInfo, boolean disableValidation) throws DiadocSdkException {
        return generateAcceptanceCertificateXmlForSeller(sellerTitleInfo, disableValidation, "rezru_05_01_02");
    }

    public GeneratedFile generateAcceptanceCertificate552XmlForSeller(AcceptanceCertificate552SellerTitleInfo sellerTitleInfo) throws DiadocSdkException {
        return generateAcceptanceCertificateXmlForSeller(sellerTitleInfo, false, "rezru_05_01_02");
    }

    private <T extends GeneratedMessage> GeneratedFile generateAcceptanceCertificateXmlForSeller(T sellerTitleInfo, boolean disableValidation, @Nullable String documentVersion)
            throws DiadocSdkException {

        if (sellerTitleInfo == null) {
            throw new IllegalArgumentException("sellerTitleInfo");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GenerateAcceptanceCertificateXmlForSeller")
                            .addParameter("disableValidation", String.valueOf(disableValidation))
                            .addParameter("documentVersion", documentVersion)
                            .build())
                    .setEntity(new ByteArrayEntity(sellerTitleInfo.toByteArray()));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateAcceptanceCertificateXmlForBuyer(AcceptanceCertificateBuyerTitleInfo buyerTitleInfo,
                                                                  String boxId,
                                                                  String sellerTitleMessageId,
                                                                  String sellerTitleAttachmentId) throws DiadocSdkException {
        return generateAcceptanceCertificateXmlForBuyer(buyerTitleInfo, boxId, sellerTitleMessageId, sellerTitleAttachmentId, null);
    }

    public GeneratedFile generateAcceptanceCertificate552XmlForBuyer(AcceptanceCertificate552BuyerTitleInfo buyerTitleInfo,
                                                                     String boxId,
                                                                     String sellerTitleMessageId,
                                                                     String sellerTitleAttachmentId) throws DiadocSdkException {

        return generateAcceptanceCertificateXmlForBuyer(buyerTitleInfo, boxId, sellerTitleMessageId, sellerTitleAttachmentId, "rezru_05_01_02");
    }


    private <T extends GeneratedMessage> GeneratedFile generateAcceptanceCertificateXmlForBuyer(
            T buyerTitleInfo,
            String boxId,
            String sellerTitleMessageId,
            String sellerTitleAttachmentId,
            @Nullable String documentVersion) throws DiadocSdkException {
        if (buyerTitleInfo == null) {
            throw new IllegalArgumentException("buyerTitleInfo");
        }
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (sellerTitleMessageId == null) {
            throw new IllegalArgumentException("sellerTitleMessageId");
        }
        if (sellerTitleAttachmentId == null) {
            throw new IllegalArgumentException("sellerTitleAttachmentId");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GenerateAcceptanceCertificateXmlForBuyer")
                            .addParameter("boxId", boxId)
                            .addParameter("sellerTitleMessageId", sellerTitleMessageId)
                            .addParameter("sellerTitleAttachmentId", sellerTitleAttachmentId)
                            .addParameter("documentVersion", documentVersion)
                            .build())
                    .setEntity(new ByteArrayEntity(buyerTitleInfo.toByteArray()));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateUniversalTransferDocumentXmlForSeller(UniversalTransferDocumentSellerTitleInfo utdInfo) throws DiadocSdkException {
        return generateUniversalTransferDocumentXmlForSeller(utdInfo, false);
    }

    public GeneratedFile generateUniversalTransferDocumentXmlForSeller(UniversalTransferDocumentSellerTitleInfo utdInfo, boolean disableValidation) throws DiadocSdkException {
        return generateUniversalTransferDocumentXmlForSeller(utdInfo, disableValidation, "utd_05_01_05");
    }

    public GeneratedFile generateUniversalTransferDocumentXmlForSeller(UniversalTransferDocumentSellerTitleInfo utdInfo, boolean disableValidation, String documentVersion) throws DiadocSdkException {
        if (utdInfo == null) {
            throw new IllegalArgumentException("info");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GenerateUniversalTransferDocumentXmlForSeller")
                            .addParameter("documentVersion", documentVersion)
                            .addParameter("disableValidation", String.valueOf(disableValidation))
                            .build())
                    .setEntity(new ByteArrayEntity(utdInfo.toByteArray()));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateUniversalTransferDocumentXmlForBuyer(
            UniversalTransferDocumentBuyerTitleInfo buyerTitleInfo,
            String boxId,
            String sellerTitleMessageId,
            String sellerTitleAttachmentId
    ) throws DiadocSdkException {
        if (buyerTitleInfo == null) {
            throw new IllegalArgumentException("buyerTitleInfo");
        }
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (sellerTitleMessageId == null) {
            throw new IllegalArgumentException("sellerTitleMessageId");
        }
        if (sellerTitleAttachmentId == null) {
            throw new IllegalArgumentException("sellerTitleAttachmentId");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GenerateUniversalTransferDocumentXmlForBuyer")
                            .addParameter("boxId", boxId)
                            .addParameter("sellerTitleMessageId", sellerTitleMessageId)
                            .addParameter("sellerTitleAttachmentId", sellerTitleAttachmentId)
                            .build())
                    .setEntity(new ByteArrayEntity(buyerTitleInfo.toByteArray()));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateUniversalCorrectionTransferDocumentXmlForSeller(
            UniversalCorrectionDocumentSellerTitleInfo ucdInfo,
            boolean disableValidation,
            String documentVersion) throws DiadocSdkException {
        if (ucdInfo == null) {
            throw new IllegalArgumentException("info");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GenerateUniversalTransferDocumentXmlForSeller")
                            .addParameter("correction", null)
                            .addParameter("documentVersion", documentVersion)
                            .addParameter("disableValidation", String.valueOf(disableValidation))
                            .build())
                    .setEntity(new ByteArrayEntity(ucdInfo.toByteArray()));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    public GeneratedFile generateUniversalCorrectionTransferDocumentXmlForSeller(UniversalCorrectionDocumentSellerTitleInfo ucdInfo) throws DiadocSdkException {
        return generateUniversalCorrectionTransferDocumentXmlForSeller(ucdInfo, false);
    }

    public GeneratedFile generateUniversalCorrectionTransferDocumentXmlForSeller(UniversalCorrectionDocumentSellerTitleInfo ucdInfo, boolean disableValidation) throws DiadocSdkException {
        return generateUniversalCorrectionTransferDocumentXmlForSeller(ucdInfo, disableValidation, "ucd_05_01_03");
    }

    @Deprecated
    private GeneratedFile generateDocumentReceiptXml(String boxId, String messageId, String attachmentId, Signer signer, String path)
            throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (messageId == null) {
            throw new IllegalArgumentException("messageId");
        }
        if (attachmentId == null) {
            throw new IllegalArgumentException("attachmentId");
        }
        if (signer == null) {
            throw new IllegalArgumentException("signer");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath(path)
                            .addParameter("boxId", boxId)
                            .addParameter("messageId", messageId)
                            .addParameter("attachmentId", attachmentId)
                            .build())
                    .setEntity(new ByteArrayEntity(signer.toByteArray()));
            return diadocHttpClient.performRequestWithGeneratedFile(request);
        } catch (URISyntaxException | IOException | ParseException e) {
            throw new DiadocSdkException(e);
        }
    }

    @Deprecated
    public GeneratedFile generateInvoiceDocumentReceiptXml(String boxId, String messageId, String attachmentId, Signer signer)
            throws DiadocSdkException {
        return  generateDocumentReceiptXml(boxId, messageId, attachmentId, signer, "/GenerateInvoiceDocumentReceiptXml");
    }

    @Deprecated
    public GeneratedFile generateDocumentReceiptXml(String boxId, String messageId, String attachmentId, Signer signer) throws DiadocSdkException {
        return generateDocumentReceiptXml(boxId, messageId, attachmentId, signer, "/GenerateDocumentReceiptXml");
    }
} public class DiadocHttpClient {

    private CloseableHttpClient httpClient;
    private String baseUrl;

    public DiadocHttpClient(
            CredentialsProvider credentialsProvider,
            String baseUrl,
            @Nullable HttpHost proxyHost,
            @Nullable ConnectionSettings connectionSettings) {
        var sslSocketFactory = getTrustfulSslSocketFactory();

        var connectionManager = new PoolingHttpClientConnectionManager(
                RegistryBuilder.<ConnectionSocketFactory>create()
                        .register("https", sslSocketFactory)
                        .register("http", new PlainConnectionSocketFactory())
                        .build());
        if(connectionSettings != null) {
            connectionManager.setMaxTotal(connectionSettings.getMaxTotalConnections());
            connectionManager.setDefaultMaxPerRoute(connectionSettings.getMaxConnectionsPerRoute());
        }
        var httpClientBuilder = HttpClients
                .custom()
                .setSSLSocketFactory(sslSocketFactory)
                .setConnectionManager(connectionManager)
                .setUserAgent(EnvironmentHelpers.getUserAgentString())
                .addInterceptorFirst(new DiadocPreemptiveAuthRequestInterceptor())
                .addInterceptorLast(new ContentLengthInterceptor())
                .setDefaultCredentialsProvider(credentialsProvider);

        if (proxyHost != null) {
            httpClientBuilder.setProxy(proxyHost);
        }

        httpClient = httpClientBuilder.build();
        this.baseUrl = baseUrl;
    }

    public String getBaseUrl() {
        return baseUrl;
    }

    public byte[] performRequest(RequestBuilder requestBuilder) throws IOException {
        try (var response = httpClient.execute(createRequest(requestBuilder))) {
            return getResponseBytes(response);
        }
    }

    public GeneratedFile performRequestWithGeneratedFile(RequestBuilder requestBuilder) throws IOException, ParseException {
        try (var response = httpClient.execute(createRequest(requestBuilder))) {
            return new GeneratedFile(tryGetHttpResponseFileName(response), getResponseBytes(response));
        }
    }

    public FileContent performRequestWithFileContent(RequestBuilder requestBuilder) throws IOException {
        try (var response = httpClient.execute(createRequest(requestBuilder))) {
            return new FileContent(getResponseBytes(response), tryGetFileContentName(response));
        }
    }

    public DiadocResponseInfo getResponse(RequestBuilder requestBuilder) throws IOException {
        try (var response = httpClient.execute(createRequest(requestBuilder))) {
            return getResponse(response);
        }
    }

    public DiadocResponseInfo getRawResponse(RequestBuilder requestBuilder) throws IOException, ParseException {
        try (var response = httpClient.execute(createRequest(requestBuilder))) {
            return getRawResponse(response);
        }
    }

    private byte[] getResponseBytes(HttpResponse response) throws IOException {
        if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
            throw new HttpResponseException(
                    response.getStatusLine().getStatusCode(),
                    new String(IOUtils.toByteArray(response.getEntity().getContent())));
        }
        return IOUtils.toByteArray(response.getEntity().getContent());
    }

    private DiadocResponseInfo getResponse(HttpResponse response) throws IOException {
        if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
            return DiadocResponseInfo.fail(
                    response.getStatusLine().getStatusCode(),
                    new String(IOUtils.toByteArray(response.getEntity().getContent())),
                    tryGetRetryAfter(response));
        }
        return DiadocResponseInfo.success(IOUtils.toByteArray(response.getEntity().getContent()), response.getStatusLine().getStatusCode());
    }

    private DiadocResponseInfo getRawResponse(HttpResponse response) throws IOException, ParseException {
        var statusCode = response.getStatusLine().getStatusCode();
        if (statusCode < HttpStatus.SC_OK || statusCode >= HttpStatus.SC_BAD_REQUEST) {
            throw new HttpResponseException(
                    statusCode,
                    new String(IOUtils.toByteArray(response.getEntity().getContent())));
        }
        return new DiadocResponseInfo(
                response.getEntity() != null && response.getEntity().getContent() != null
                        ? IOUtils.toByteArray(response.getEntity().getContent())
                        : null,
                tryGetRetryAfter(response),
                statusCode,
                response.getStatusLine().getReasonPhrase(),
                tryGetHttpResponseFileName(response),
                tryGetContentType(response));
    }

    private HttpUriRequest createRequest(RequestBuilder requestBuilder) {
        var requestConfig = RequestConfig.custom().setAuthenticationEnabled(false).build();
        return requestBuilder.setConfig(requestConfig).build();
    }

    private HttpUriRequest createWaitRequest(String path, String taskId) throws URISyntaxException {
        return createRequest(RequestBuilder.get(
                new URIBuilder(baseUrl)
                        .setPath(path)
                        .addParameter("taskId", taskId)
                        .build()));
    }

    @Nullable
    private static String tryGetContentType(HttpResponse response) {
        if (response.getEntity() != null && response.getEntity().getContentType() != null) {
            return response.getEntity().getContentType().getValue();
        }
        return null;
    }

    private static SSLConnectionSocketFactory getTrustfulSslSocketFactory() {
        try {
            var ctx = SSLContextBuilder.create().loadTrustMaterial(new TrustAllStrategy()).build();
            return new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE);
        } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
            e.printStackTrace();
            throw new RuntimeException("Can't create ssl connection factory", e);
        }
    }

    public byte[] waitTaskResult(String path, String taskId, @Nullable Integer timeoutInMillis) throws DiadocSdkException {
        if (timeoutInMillis == null) {
            timeoutInMillis = 5 * 60 * 1000;
        }
        var timeLimit = new Date(new Date().getTime() + timeoutInMillis).getTime();

        try {
            while (true) {
                try (var response = httpClient.execute(createWaitRequest(path, taskId))) {
                    var statusCode = response.getStatusLine().getStatusCode();
                    if (statusCode == HttpStatus.SC_NO_CONTENT) {
                        if (new Date().getTime() > timeLimit) {
                            throw new TimeoutException(String.format("Can't GET '%s'. Timeout %ds expired.", path, timeLimit / 1000));
                        }
                        var retryAfter = tryGetRetryAfter(response);
                        int delayInSeconds = retryAfter != null
                                ? Math.min(retryAfter, 15)
                                : 15;
                        Thread.sleep(delayInSeconds * 1000);
                        continue;
                    }
                    if (statusCode != HttpStatus.SC_OK) {
                        throw new DiadocException(response.getStatusLine().getReasonPhrase(), statusCode, tryGetDiadocErrorCode(response));
                    }
                    return getResponseBytes(response);
                }
            }
        } catch (IOException | URISyntaxException | TimeoutException | InterruptedException | DiadocException e) {
            e.printStackTrace();
            throw new DiadocSdkException(e);
        }
    }

    @Nullable
    private static Integer tryGetRetryAfter(HttpResponse response) {
        Header[] retryAfterHeaders = response.getHeaders(HttpHeaders.RETRY_AFTER);
        if (retryAfterHeaders.length > 0) {
            String retryAfterStr = retryAfterHeaders[0].getValue();
            if (!Tools.isNullOrEmpty(retryAfterStr)) {
                return Integer.parseInt(retryAfterStr);
            }
        }
        return null;
    }

    @Nullable
    private static String tryGetDiadocErrorCode(HttpResponse webResponse) {
        Header[] errorCodeHeaders = webResponse.getHeaders("X-Diadoc-ErrorCode");
        if (errorCodeHeaders.length > 0) {
            return errorCodeHeaders[0].getValue();
        }
        return null;
    }

    @Nullable
    private static String tryGetHttpResponseFileName(HttpResponse webResponse) throws ParseException {
        Header[] dispositions = webResponse.getHeaders("Content-Disposition");
        if (dispositions == null || dispositions.length == 0)
            return null;
        return new ContentDisposition(dispositions[0].getValue()).getParameter("filename");
    }

    @Nullable
    private static String tryGetFileContentName(HttpResponse response) {
        Header fileNameHeader = response.getFirstHeader("X-Diadoc-FileName");
        return fileNameHeader == null ? null : fileNameHeader.getValue();
    }
} public class MessageClient {
    private DiadocHttpClient diadocHttpClient;

    public MessageClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public Message postMessage(MessageToPost msg) throws DiadocSdkException {
        return postMessage(msg, null);
    }

    public Message postMessage(MessageToPost msg, @Nullable String operationId) throws DiadocSdkException {
        if (msg == null) {
            throw new IllegalArgumentException("msg");
        }
        try {
            var uriBuilder = new URIBuilder(diadocHttpClient.getBaseUrl()).setPath("/V3/PostMessage");
            if (operationId != null) {
                uriBuilder.addParameter("operationId", operationId);
            }
            var request = RequestBuilder
                    .post(uriBuilder.build())
                    .setEntity(new ByteArrayEntity(msg.toByteArray()));

            return Message.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Message getMessage(String currentBoxId, String messageId, @Nullable String entityId, boolean withOriginalSignature, boolean injectEntityContent) throws DiadocSdkException {
        if (currentBoxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (messageId == null) {
            throw new IllegalArgumentException("messageId");
        }

        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/V5/GetMessage")
                    .addParameter("boxId", currentBoxId)
                    .addParameter("messageId", messageId)
                    .addParameter("injectEntityContent", String.valueOf(injectEntityContent))
                    .addParameter("originalSignature", String.valueOf(withOriginalSignature));

            if (!Tools.isNullOrEmpty(entityId)) {
                url.addParameter("entityId", entityId);
            }

            var request = RequestBuilder.get(url.build());
            return Message.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Message getMessage(String currentBoxId, String messageId, String entityId) throws DiadocSdkException {
        return getMessage(currentBoxId, messageId, entityId, false, false);
    }

    public Message getMessage(String currentBoxId, String messageId, String entityId, boolean withOriginalSignature) throws DiadocSdkException {
        return getMessage(currentBoxId, messageId, entityId, withOriginalSignature, false);
    }

    public Message getMessage(String currentBoxId, String messageId, boolean withOriginalSignature, boolean injectEntityContent) throws DiadocSdkException {
        return getMessage(currentBoxId, messageId, null, withOriginalSignature, injectEntityContent);
    }

    public Message getMessage(String currentBoxId, String messageId) throws DiadocSdkException {
        return getMessage(currentBoxId, messageId, false, false);
    }

    public Message getMessage(String currentBoxId, String messageId, boolean withOriginalSignature) throws DiadocSdkException {
        return getMessage(currentBoxId, messageId, withOriginalSignature, false);
    }

    public MessagePatch postMessagePatch(MessagePatchToPost patch) throws DiadocSdkException {
        return postMessagePatch(patch, null);
    }

    public MessagePatch postMessagePatch(MessagePatchToPost patch, @Nullable String operationId) throws DiadocSdkException {
        if (patch == null) {
            throw new IllegalArgumentException("patch");
        }

        try {
            var uriBuilder = new URIBuilder(diadocHttpClient.getBaseUrl()).setPath("/V3/PostMessagePatch");
            if (operationId != null) {
                uriBuilder.addParameter("operationId", operationId);
            }
            var request = RequestBuilder
                    .post(uriBuilder.build())
                    .setEntity(new ByteArrayEntity(patch.toByteArray()));

            return MessagePatch.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public void delete(String boxId, String messageId, String documentId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (messageId == null) {
            throw new IllegalArgumentException("messageId");
        }
        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/Delete")
                    .addParameter("boxId", boxId)
                    .addParameter("messageId", messageId);

            if (!Tools.isNullOrEmpty(documentId)) {
                url.addParameter("entityId", documentId);
            }

            var request = RequestBuilder
                    .post(url.build())
                    .setHeader("Content-Length", "0");

            diadocHttpClient.performRequest(request);
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Message sendDraft(DraftToSend draftToSend) throws DiadocSdkException {
        return sendDraft(draftToSend, null);
    }

    public Message sendDraft(DraftToSend draftToSend, @Nullable String operationId) throws DiadocSdkException {
        if (draftToSend == null) {
            throw new IllegalArgumentException("draftToSend");
        }
        try {
            var uriBuilder = new URIBuilder(diadocHttpClient.getBaseUrl()).setPath("/SendDraft");
            if (operationId != null) {
                uriBuilder.addParameter("operationId", operationId);
            }
            var request = RequestBuilder
                    .post(uriBuilder.build())
                    .setEntity(new ByteArrayEntity(draftToSend.toByteArray()));

            return Message.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public void recycleDraft(String boxId, String draftId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (draftId == null) {
            throw new IllegalArgumentException("draftId");
        }
        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/RecycleDraft")
                            .addParameter("boxId", boxId)
                            .addParameter("draftId", draftId);
            
            var request = RequestBuilder
                    .post(url.build())
                    .setHeader("Content-Length", "0");

            diadocHttpClient.performRequest(request);
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public InvoiceCorrectionRequestInfo getInvoiceCorrectionRequestInfo(String boxId, String messageId, String entityId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (messageId == null) {
            throw new IllegalArgumentException("messageId");
        }
        if (entityId == null) {
            throw new IllegalArgumentException("entityId");
        }
        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/GetInvoiceCorrectionRequestInfo")
                    .addParameter("boxId", boxId)
                    .addParameter("messageId", messageId)
                    .addParameter("entityId", entityId);

            var request = RequestBuilder.get(url.build());
            return InvoiceCorrectionRequestInfo.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }
} public class OrganizationClient {
    private DiadocHttpClient diadocHttpClient;

    public OrganizationClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public Box getBox(String boxId) throws DiadocSdkException {
        if (boxId == null)
            throw new IllegalArgumentException("boxId");
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetBox")
                            .addParameter("boxId", boxId)
                            .build());
            return Box.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Organization getOrganizationById(String orgId) throws DiadocSdkException {
        if (orgId == null || orgId.isEmpty()) {
            throw new IllegalArgumentException("orgId");
        }
        return getOrganization("orgId", orgId);
    }

    public Organization getOrganizationByInn(String inn) throws DiadocSdkException {
        if (inn == null || inn.isEmpty()) {
            throw new IllegalArgumentException("inn");
        }
        return getOrganization("inn", inn);
    }

    public Organization getOrganizationByFnsParticipantId(String fnsParticipantId) throws DiadocSdkException {
        if (fnsParticipantId == null || fnsParticipantId.isEmpty()) {
            throw new IllegalArgumentException("fnsParticipantId");
        }
        return getOrganization("fnsParticipantId", fnsParticipantId);
    }

    public OrganizationWithCounteragentStatus[] getOrganizationsByInnList(String myOrgId, Iterable<String> innList) throws DiadocSdkException {
        var request = GetOrganizationsByInnListRequest.newBuilder();
        request.addAllInnList(innList);
        return getOrganizationsByInnList(myOrgId, request.build());
    }

    public OrganizationWithCounteragentStatus[] getOrganizationsByInnList(String myOrgId, GetOrganizationsByInnListRequest innListRequest) throws DiadocSdkException {
        if (myOrgId == null)
            throw new IllegalArgumentException("myOrgId");
        if (innListRequest == null)
            throw new IllegalArgumentException("innListRequest");
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetOrganizationsByInnList")
                            .addParameter("myOrgId", myOrgId)
                            .build())
                    .setEntity(new ByteArrayEntity(innListRequest.toByteArray()));


            var response = GetOrganizationsByInnListResponse.parseFrom(diadocHttpClient.performRequest(request));
            return response.getOrganizationsList().toArray(new OrganizationWithCounteragentStatus[0]);

        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Organization[] getOrganizationsByInnList(Iterable<String> innList) throws DiadocSdkException {
        var request = GetOrganizationsByInnListRequest.newBuilder();
        request.addAllInnList(innList);
        return getOrganizationsByInnList(request.build());
    }

    public Organization[] getOrganizationsByInnList(GetOrganizationsByInnListRequest innListRequest) throws DiadocSdkException {
        if (innListRequest == null) {
            throw new IllegalArgumentException("innListRequest");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetOrganizationsByInnList")
                            .build())
                    .setEntity(new ByteArrayEntity(innListRequest.toByteArray()));
            var response = GetOrganizationsByInnListResponse.parseFrom(diadocHttpClient.performRequest(request));
            return response
                    .getOrganizationsList()
                    .stream()
                    .map(OrganizationWithCounteragentStatus::getOrganization)
                    .toArray(Organization[]::new);
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public OrganizationList getOrganizationsByInnKpp(String inn, @Nullable String kpp, boolean includeRelations) throws DiadocSdkException {
        if (inn == null) {
            throw new IllegalArgumentException("inn");
        }
        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/GetOrganizationsByInnKpp")
                    .addParameter("inn", inn);

            if (!Tools.isNullOrEmpty(kpp)) {
                url.addParameter("kpp", kpp);
            }

            if (includeRelations) {
                url.addParameter("includeRelations", "true");
            }
            var request = RequestBuilder.get(url.build());
            return OrganizationList.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public OrganizationList getOrganizationsByInnKpp(String inn, @Nullable String kpp) throws DiadocSdkException {
        return getOrganizationsByInnKpp(inn, kpp, false);
    }

    public OrganizationList getMyOrganizations(boolean autoRegister) throws DiadocSdkException {
        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/GetMyOrganizations");

            if (!autoRegister) {
                url.addParameter("autoRegister", Boolean.toString(false));
            }
            var request = RequestBuilder.get(url.build());
            return OrganizationList.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public OrganizationList getMyOrganizations() throws DiadocSdkException {
        return getMyOrganizations(true);
    }

    public OrganizationUsersList getOrganizationUsers(String orgId) throws DiadocSdkException {
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetOrganizationUsers")
                            .addParameter("orgId", orgId)
                            .build());
            return OrganizationUsersList.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public OrganizationUserPermissions getMyPermissions(String orgId) throws DiadocSdkException {
        if (orgId == null) {
            throw new IllegalArgumentException("orgId");
        }

        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/GetMyPermissions")
                            .addParameter("orgId", orgId)
                            .build());
            return OrganizationUserPermissions.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    private Organization getOrganization(String name, String value) throws DiadocSdkException {
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(
                            diadocHttpClient.getBaseUrl())
                            .setPath("/GetOrganization")
                            .addParameter(name, value)
                            .build());

            return Organization.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public OrganizationFeatures getOrganizationFeatures(String boxId) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }

        try {
            var request = RequestBuilder.get(
                    new URIBuilder(
                            diadocHttpClient.getBaseUrl())
                            .setPath("/GetOrganizationFeatures")
                            .addParameter("boxId", boxId)
                            .build());

            return OrganizationFeatures.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public RegistrationResponse register(RegistrationRequest registrationRequest) throws DiadocSdkException {
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/Register")
                            .build())
                    .setEntity(new ByteArrayEntity(registrationRequest.toByteArray()));
            return RegistrationResponse.parseFrom(diadocHttpClient.performRequest(request));

        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public void registerConfirm(RegistrationConfirmRequest registrationConfirmRequest) throws DiadocSdkException {
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/Register")
                            .build())
                    .setEntity(new ByteArrayEntity(registrationConfirmRequest.toByteArray()));
            diadocHttpClient.performRequest(request);

        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public boolean canSendInvoice(String boxId, byte[] certBytes) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        if (certBytes == null || certBytes.length == 0) {
            throw new IllegalArgumentException("certBytes");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/CanSendInvoice")
                            .addParameter("boxId", boxId)
                            .build())
                    .setEntity(new ByteArrayEntity(certBytes));

            var response = diadocHttpClient.getResponse(request);
            switch (response.getStatusCode()) {
                case HttpStatus.SC_OK:
                    return true;
                case HttpStatus.SC_FORBIDDEN:
                    return false;
                default:
                    throw new DiadocException(response.getReason(), response.getStatusCode());
            }
        } catch (URISyntaxException | IOException | DiadocException e) {
            throw new DiadocSdkException(e);
        }
    }

} public class ParseClient {
    private DiadocHttpClient diadocHttpClient;

    public ParseClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public InvoiceInfo parseInvoiceXml(byte[] invoiceXmlContent) throws DiadocSdkException {
        try {
            return InvoiceInfo.parseFrom(parseXml(invoiceXmlContent, "/ParseInvoiceXml", null));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Torg12SellerTitleInfo parseTorg12SellerTitleXml(byte[] sellerTitleXmlContent) throws DiadocSdkException {
        try {
            return Torg12SellerTitleInfo.parseFrom(parseXml(sellerTitleXmlContent, "/ParseTorg12SellerTitleXml", null));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Torg12BuyerTitleInfo parseTorg12BuyerTitleXml(byte[] buyerTitleXmlContent) throws DiadocSdkException {
        try {
            return Torg12BuyerTitleInfo.parseFrom(parseXml(buyerTitleXmlContent, "/ParseTorg12BuyerTitleXml", null));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public TovTorgSellerTitleInfo parseTovTorg551SellerTitleXml(byte[] sellerTitleXmlContent) throws DiadocSdkException {
        try {
            return TovTorgSellerTitleInfo.parseFrom(parseXml(sellerTitleXmlContent, "/ParseTorg12SellerTitleXml", "tovtorg_05_01_04"));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public TovTorgBuyerTitleInfo parseTovTorg551BuyerTitleXml(byte[] buyerTitleXmlContent) throws DiadocSdkException {
        try {
            return TovTorgBuyerTitleInfo.parseFrom(parseXml(buyerTitleXmlContent, "/ParseTorg12BuyerTitleXml", "tovtorg_05_01_04"));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public AcceptanceCertificateSellerTitleInfo parseAcceptanceCertificateSellerTitleXml(byte[] sellerTitleXmlContent) throws DiadocSdkException {
        try {
            return AcceptanceCertificateSellerTitleInfo.parseFrom(parseXml(
                    sellerTitleXmlContent,
                    "/ParseAcceptanceCertificateSellerTitleXml",
                    null));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public AcceptanceCertificateBuyerTitleInfo parseAcceptanceCertificateBuyerTitleXml(byte[] buyerTitleXmlContent) throws DiadocSdkException {
        try {
            return AcceptanceCertificateBuyerTitleInfo.parseFrom(parseXml(
                    buyerTitleXmlContent,
                    "/ParseAcceptanceCertificateBuyerTitleXml",
                    null));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public AcceptanceCertificate552SellerTitleInfo parseAcceptanceCertificate552SellerTitleXml(byte[] sellerTitleXmlContent) throws DiadocSdkException {
        try {
            return AcceptanceCertificate552SellerTitleInfo.parseFrom(parseXml(
                    sellerTitleXmlContent,
                    "/ParseAcceptanceCertificateSellerTitleXml",
                    "rezru_05_01_02"));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public AcceptanceCertificate552BuyerTitleInfo parseAcceptanceCertificate552BuyerTitleXml(byte[] buyerTitleXmlContent) throws DiadocSdkException {
        try {
            return AcceptanceCertificate552BuyerTitleInfo.parseFrom(parseXml(
                    buyerTitleXmlContent,
                    "/ParseAcceptanceCertificateBuyerTitleXml",
                    "rezru_05_01_02"));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public UniversalTransferDocumentSellerTitleInfo parseUniversalTransferDocumentSellerTitleXml(byte[] utdXmlContent) throws DiadocSdkException {
        return parseUniversalTransferDocumentSellerTitleXml(utdXmlContent, "utd_05_01_05");
    }

    public UniversalTransferDocumentSellerTitleInfo parseUniversalTransferDocumentSellerTitleXml(byte[] utdXmlContent, String documentVersion)
            throws DiadocSdkException {
        try {
            return UniversalTransferDocumentSellerTitleInfo.parseFrom(parseXml(
                    utdXmlContent,
                    "/ParseUniversalTransferDocumentSellerTitleXml",
                    documentVersion));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public UniversalTransferDocumentBuyerTitleInfo parseUniversalTransferDocumentBuyerTitleXml(byte[] utdXmlContent) throws DiadocSdkException {
        try {
            return UniversalTransferDocumentBuyerTitleInfo.parseFrom(parseXml(
                    utdXmlContent,
                    "/ParseUniversalTransferDocumentBuyerTitleXml",
                    null));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public UniversalCorrectionDocumentSellerTitleInfo parseUniversalCorrectionDocumentSellerTitleXml(byte[] utdXmlContent) throws DiadocSdkException {
        return parseUniversalCorrectionDocumentSellerTitleXml(utdXmlContent, "ucd_05_01_03");
    }

    public UniversalCorrectionDocumentSellerTitleInfo parseUniversalCorrectionDocumentSellerTitleXml(byte[] utdXmlContent, String documentVersion) throws
            DiadocSdkException {
        try {
            return UniversalCorrectionDocumentSellerTitleInfo.parseFrom(parseXml(
                    utdXmlContent,
                    "/ParseUniversalCorrectionDocumentSellerTitleXml",
                    documentVersion));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public UniversalTransferDocumentBuyerTitleInfo parseUniversalCorrectionDocumentBuyerTitleXml(byte[] utdXmlContent) throws DiadocSdkException {
        try {
            return UniversalTransferDocumentBuyerTitleInfo.parseFrom(parseXml(
                    utdXmlContent,
                    "/ParseUniversalCorrectionDocumentBuyerTitleXml",
                    null));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public RevocationRequestInfo parseRevocationRequestXml(byte[] xmlContent) throws DiadocSdkException {
        try {
            return RevocationRequestInfo.parseFrom(parseXml(
                    xmlContent,
                    "/ParseRevocationRequestXml",
                    null));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public SignatureRejectionInfo parseSignatureRejectionXml(byte[] xmlContent) throws DiadocSdkException {

        try {
            return SignatureRejectionInfo.parseFrom(parseXml(
                    xmlContent,
                    "/ParseSignatureRejectionXml",
                    null));
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public byte[] parseTitleXml(String boxId, String documentTypeNamedId, String documentFunction, String documentVersion, Integer titleIndex, byte[] content) throws IOException, DiadocSdkException {
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/ParseTitleXml")
                            .addParameter("boxId", boxId)
                            .addParameter("documentTypeNamedId", documentTypeNamedId)
                            .addParameter("documentFunction", documentFunction)
                            .addParameter("documentVersion", documentVersion)
                            .addParameter("titleIndex", titleIndex.toString()).build())
                    .setEntity(new ByteArrayEntity(content));

            return diadocHttpClient.performRequest(request);
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    private byte[] parseXml(byte[] xmlContent, String path, @Nullable String documentVersion) throws DiadocSdkException {
        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl()).setPath(path);

            if (documentVersion != null) {
                url.addParameter("documentVersion", documentVersion);
            }

            var request = RequestBuilder.post(
                    url.build())
                    .setEntity(new ByteArrayEntity(xmlContent));

            return diadocHttpClient.performRequest(request);
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }
} public class PrintFormClient {
    private DiadocHttpClient diadocHttpClient;

    public PrintFormClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public PrintFormResult generatePrintForm(String boxId, String messageId, String documentId) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        if (Tools.isNullOrEmpty(messageId)) {
            throw new IllegalArgumentException("messageId");
        }
        if (Tools.isNullOrEmpty(documentId)) {
            throw new IllegalArgumentException("documentId");
        }

        try {
            var request = RequestBuilder.get(new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/GeneratePrintForm")
                    .addParameter("boxId", boxId)
                    .addParameter("messageId", messageId)
                    .addParameter("documentId", documentId)
                    .build());

            var response = diadocHttpClient.getRawResponse(request);

            if (response.getRetryAfter() != null) {
                return new PrintFormResult(response.getRetryAfter());
            }

            return new PrintFormResult(new PrintFormContent(response.getContentType(), response.getFileName(), response.getContent()));

        } catch (URISyntaxException | ParseException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public CustomPrintFormDetectionResult detectCustomPrintForms(String boxId, CustomPrintFormDetectionRequest detectionRequest) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        if (detectionRequest == null || detectionRequest.getDocumentIdsCount() == 0) {
            throw new IllegalArgumentException("detectionRequest");
        }
        try {
            var request = RequestBuilder.post(new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/DetectCustomPrintForms")
                    .addParameter("boxId", boxId)
                    .build())
                    .setEntity(new ByteArrayEntity(detectionRequest.toByteArray()));


            return CustomPrintFormDetectionResult.parseFrom(diadocHttpClient.performRequest(request));

        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public DocumentZipResult generateDocumentZip(String boxId, String messageId, String documentId, boolean fullDocflow) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        if (Tools.isNullOrEmpty(messageId)) {
            throw new IllegalArgumentException("messageId");
        }
        if (Tools.isNullOrEmpty(documentId)) {
            throw new IllegalArgumentException("documentId");
        }
        try {
            var request = RequestBuilder.get(new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/GenerateDocumentZip")
                    .addParameter("boxId", boxId)
                    .addParameter("messageId", messageId)
                    .addParameter("documentId", documentId)
                    .addParameter("fullDocflow", String.valueOf(fullDocflow))
                    .build());

            var response = diadocHttpClient.getRawResponse(request);

            if (response.getRetryAfter() != null) {
                return new DocumentZipResult(response.getRetryAfter());
            }

            return new DocumentZipResult(DocumentZipGenerationResult.parseFrom(response.getContent()));

        } catch (URISyntaxException | ParseException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public DocumentProtocolResult generateDocumentProtocol(String boxId, String messageId, String documentId) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(boxId)) {
            throw new IllegalArgumentException("boxId");
        }
        if (Tools.isNullOrEmpty(messageId)) {
            throw new IllegalArgumentException("messageId");
        }
        if (Tools.isNullOrEmpty(documentId)) {
            throw new IllegalArgumentException("documentId");
        }

        try {
            var request = RequestBuilder.get(new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/GenerateDocumentProtocol")
                    .addParameter("boxId", boxId)
                    .addParameter("messageId", messageId)
                    .addParameter("documentId", documentId)
                    .build());

            var response = diadocHttpClient.getRawResponse(request);

            if (response.getRetryAfter() != null) {
                return new DocumentProtocolResult(response.getRetryAfter());
            }

            return new DocumentProtocolResult(DocumentProtocol.parseFrom(response.getContent()));

        } catch (URISyntaxException | ParseException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public PrintFormResult generatePrintFormFromAttachment(String fromBoxId, String documentType, byte[] bytes) throws DiadocSdkException {
        if (Tools.isNullOrEmpty(fromBoxId)) {
            throw new IllegalArgumentException("fromBoxId");
        }
        if (Tools.isNullOrEmpty(documentType)) {
            throw new IllegalArgumentException("documentType");
        }
        if (bytes == null) {
            throw new IllegalArgumentException("bytes");
        }

        try {
            var request = RequestBuilder.get(new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/GeneratePrintFormFromAttachment")
                    .addParameter("fromBoxId", fromBoxId)
                    .addParameter("documentType", documentType)
                    .build())
                    .setEntity(new ByteArrayEntity(bytes));

            var response = diadocHttpClient.getRawResponse(request);

            if (response.getRetryAfter() != null) {
                return new PrintFormResult(response.getRetryAfter());
            }

            return new PrintFormResult(new PrintFormContent(response.getContentType(), response.getFileName(), response.getContent()));

        } catch (URISyntaxException | ParseException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public PrintFormResult getGeneratedPrintForm(String printFormId) throws DiadocSdkException {
        try {
            var request = RequestBuilder.get(new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/GetGeneratedPrintForm")
                    .addParameter("printFormId", printFormId)
                    .build());

            var response = diadocHttpClient.getRawResponse(request);

            if (response.getRetryAfter() != null) {
                return new PrintFormResult(response.getRetryAfter());
            }

            return new PrintFormResult(new PrintFormContent(response.getContentType(), response.getFileName(), response.getContent()));

        } catch (URISyntaxException | ParseException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }
} public class ShelfClient {
    private DiadocHttpClient diadocHttpClient;

    private static final int SHELF_PART_LENGTH = 512 * 1024;
    private static final int SHELF_MAX_ATTEMPTS = 3;
    private static final List<Integer> SHELF_NON_RETRIABLE_STATUS_CODES = Arrays.asList(HttpStatus.SC_UNAUTHORIZED, HttpStatus.SC_FORBIDDEN, HttpStatus.SC_PAYMENT_REQUIRED);
    private static final String SHELF_PATH_PREFIX = "__userId__";

    public ShelfClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public int getShelfUploadChunkSize() {
        return SHELF_PART_LENGTH;
    }

    public int getShelfUploadMaxAttemptsCount() {
        return SHELF_MAX_ATTEMPTS;
    }

    public byte[] shelfDownload(String nameOnShelf) throws DiadocSdkException {
        if (!nameOnShelf.contains(SHELF_PATH_PREFIX))
            nameOnShelf = SHELF_PATH_PREFIX + "/" + nameOnShelf;
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/ShelfDownload")
                            .addParameter("nameOnShelf", nameOnShelf)
                            .build());
            return diadocHttpClient.performRequest(request);
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public String uploadFileToShelf(byte[] data) throws DiadocSdkException {
        if (data == null)
            throw new IllegalArgumentException("data");

        var nameOnShelf = createNameOnShelf();
        var parts = splitDataIntoParts(data);
        List<Integer> missingParts = new ArrayList<>();

        for (int i = 0; i < parts.size(); i++)
            missingParts.add(i);

        var httpErrors = new ArrayList<Exception>();
        int attempts = 0;
        while (missingParts.size() > 0) {
            if (++attempts > SHELF_MAX_ATTEMPTS)
                throw new DiadocSdkException("Reached the limit of attempts to send a file. " + formatHttpErrors(httpErrors));

            int partsCount = parts.size();
            int lastPartIndex = partsCount - 1;
            //always add last part for stability
            if (!missingParts.contains(lastPartIndex))
                missingParts.add(lastPartIndex);

            try {
                missingParts = putMissingParts(nameOnShelf, parts, missingParts, partsCount, httpErrors);
            } catch (URISyntaxException | DiadocException | IOException e) {
                e.printStackTrace();
                throw new DiadocSdkException(e);
            }
        }
        return nameOnShelf;
    }

    private String createNameOnShelf() {
        return String.format("java_api-%s", UUID.randomUUID().toString().replaceAll("-", ""));
    }

    private List<Integer> putMissingParts(
            String nameOnShelf,
            List<ByteArraySegment> allParts,
            List<Integer> missingParts,
            int partsCount,
            List<Exception> httpErrors) throws URISyntaxException, DiadocException, IOException {
        Set<Integer> lastMissingParts = new HashSet<>(missingParts);
        int maxProcessedPartIndex = -1;

        for (int partIndex : missingParts) {
            boolean isLastPart = partIndex == partsCount - 1;
            List<Integer> newMissingParts = putPart(nameOnShelf, allParts.get(partIndex), partIndex, isLastPart, httpErrors);
            if (newMissingParts != null) {
                if (partIndex > maxProcessedPartIndex) {
                    lastMissingParts.clear();
                    lastMissingParts.addAll(newMissingParts);

                    maxProcessedPartIndex = partIndex;
                }
            } else {
                lastMissingParts.add(partIndex);
            }
        }
        return new ArrayList<>(lastMissingParts);
    }

    private List<Integer> putPart(String nameOnShelf, ByteArraySegment part, int partIndex, boolean isLastPart, List<Exception> httpErrors) throws URISyntaxException, DiadocException, IOException {
        var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                .setPath("/ShelfUpload")
                .addParameter("nameOnShelf", String.format("%s/%s", SHELF_PATH_PREFIX, nameOnShelf))
                .addParameter("partIndex", Integer.toString(partIndex));

        if (isLastPart) {
            url.addParameter("isLastPart", "1");
        }

        byte[] responseContent;

        try {
            var response = diadocHttpClient.getResponse(RequestBuilder.post(url.build()).setEntity(new ByteArrayEntity(part.getBytes())));
            if (response.getStatusCode() != HttpStatus.SC_OK) {
                if (SHELF_NON_RETRIABLE_STATUS_CODES.contains(response.getStatusCode())) {
                    throw new DiadocException(formatResponseMessage(response.getReason(), response.getStatusCode()), response.getStatusCode());
                }

                httpErrors.add(new DiadocException(formatResponseMessage(response.getReason(), response.getStatusCode()), response.getStatusCode()));
                return null;
            }

            responseContent = response.getContent();

        } catch (IOException e) {
            httpErrors.add(e);
            return null;
        }

        if (responseContent == null || responseContent.length == 0)
            return null;

        String responseString = new String(responseContent, StandardCharsets.UTF_8);

        int[] missingParts = new Gson().fromJson(responseString, int[].class);
        return Arrays.stream(missingParts).boxed().collect(Collectors.toList());
    }

    private ArrayList<ByteArraySegment> splitDataIntoParts(byte[] data) {
        ArrayList<ByteArraySegment> result = new ArrayList<>();
        int currentPartOffset = 0;
        while (currentPartOffset < data.length) {
            int length = Math.min(data.length - currentPartOffset, SHELF_PART_LENGTH);
            result.add(new ByteArraySegment(data, currentPartOffset, length));
            currentPartOffset += length;
        }
        return result;
    }

    private String formatResponseMessage(String reason, int statusCode) {
        return String.format("Status code:%s%sMessage:%s%s",
                statusCode,
                System7Emu.lineSeparator(),
                reason,
                System7Emu.lineSeparator());
    }

    private String formatHttpErrors(List<Exception> errors) {
        String text = super.toString();
        for (int i = 0; i < errors.size(); i++) {
            text = String.format("%s%s---> (Inner Exception #%s) %s%s%s", text, System7Emu.lineSeparator(), i, errors.get(i).toString(), "<---", System7Emu.lineSeparator());
        }
        return text;
    }
} public class SignClient {
    private DiadocHttpClient diadocHttpClient;

    public SignClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public AsyncMethodResult cloudSign(CloudSignRequest request) throws DiadocSdkException {
        return cloudSign(request, null);
    }

    public AsyncMethodResult cloudSign(CloudSignRequest cloudSignRequest, @Nullable String certificateThumbprint) throws DiadocSdkException {
        if (cloudSignRequest == null) {
            throw new IllegalArgumentException("cloudSignRequest");
        }
        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl()).setPath("/CloudSign");

            if (certificateThumbprint != null) {
                url.addParameter("certificateThumbprint", certificateThumbprint);
            }
            var result = diadocHttpClient.performRequest(RequestBuilder.post(url.build()).setEntity(new ByteArrayEntity(cloudSignRequest.toByteArray())));
            return AsyncMethodResult.parseFrom(result);

        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public CloudSignResult waitCloudSignResult(String taskId, Integer timeoutInMillis) throws DiadocSdkException {
        try {
            var data = diadocHttpClient.waitTaskResult("/CloudSignResult", taskId, timeoutInMillis);
            return CloudSignResult.parseFrom(data);
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public AsyncMethodResult cloudSignConfirm(String token, String confirmationCode, boolean returnContent) throws DiadocSdkException {
        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/CloudSignConfirm")
                    .addParameter("token", token)
                    .addParameter("confirmationCode", confirmationCode)
                    .addParameter("return", returnContent ? "Content" : "Reference");
            var result = diadocHttpClient.performRequest(
                    RequestBuilder.post(url.build()).addHeader("Content-Length", "0"));
            return AsyncMethodResult.parseFrom(result);

        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public CloudSignConfirmResult waitCloudSignConfirmResult(String taskId, Integer timeoutInMillis) throws DiadocSdkException {
        try {
            byte[] data = diadocHttpClient.waitTaskResult("/CloudSignConfirmResult", taskId, timeoutInMillis);
            return CloudSignConfirmResult.parseFrom(data);
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }
    }

    public AsyncMethodResult autoSignReceipts(String boxId, @Nullable String certificateThumbprint, @Nullable String batchKey) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }

        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/AutoSignReceipts")
                    .addParameter("boxId", boxId);

            if (certificateThumbprint != null) {
                url.addParameter("certificateThumbprint", certificateThumbprint);
            }

            if (batchKey != null) {
                url.addParameter("batchKey", batchKey);
            }

            var result = diadocHttpClient.performRequest(
                    RequestBuilder.post(url.build()).addHeader("Content-Length", "0"));
            return AsyncMethodResult.parseFrom(result);

        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public AutosignReceiptsResult waitAutosignReceiptsResult(String taskId, Integer timeoutInMillis)
            throws DiadocSdkException {
        try {
            byte[] data = diadocHttpClient.waitTaskResult("/AutosignReceiptsResult", taskId, timeoutInMillis);
            return AutosignReceiptsResult.parseFrom(data);
        } catch (InvalidProtocolBufferException e) {
            throw new DiadocSdkException(e);
        }

    }

    public AsyncMethodResult dssSign(String boxId, DssSignRequest request) throws DiadocSdkException {
        return dssSign(boxId, request, null);
    }

    public AsyncMethodResult dssSign(String boxId, DssSignRequest request, @Nullable String certificateThumbprint) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (request == null) {
            throw new IllegalArgumentException("request");
        }

        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/DssSign")
                    .addParameter("boxId", boxId);

            if (certificateThumbprint != null) {
                url.addParameter("certificateThumbprint", certificateThumbprint);
            }


            var result = diadocHttpClient.performRequest(
                    RequestBuilder.post(url.build())
                            .setEntity(new ByteArrayEntity(request.toByteArray())));
            return AsyncMethodResult.parseFrom(result);

        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public DssSignResult dssSignResult(String boxId, String taskId) throws Exception {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (taskId == null) {
            throw new IllegalArgumentException("taskId");
        }
        try {
            var result = diadocHttpClient.performRequest(
                    RequestBuilder.get(
                            new URIBuilder(diadocHttpClient.getBaseUrl())
                                    .setPath("/DssSignResult")
                                    .addParameter("boxId", boxId)
                                    .addParameter("taskId", taskId).build()));
            return DssSignResult.parseFrom(result);

        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public ExtendedSignerDetails getExtendedSignerDetails(String boxId, String thumbprint, DocumentTitleType documentTitleType) throws DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (thumbprint == null) {
            throw new IllegalArgumentException("thumbprint");
        }

        try {
            var result = diadocHttpClient.performRequest(
                    RequestBuilder.get(
                            new URIBuilder(diadocHttpClient.getBaseUrl())
                                    .setPath("/V2/ExtendedSignerDetails")
                                    .addParameter("boxId", boxId)
                                    .addParameter("thumbprint", thumbprint)
                                    .addParameter("documentTitleType", Integer.toString(documentTitleType.getNumber())).build()));
            return ExtendedSignerDetails.parseFrom(result);

        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public ExtendedSignerDetails postExtendedSignerDetails(String boxId, String thumbprint, DocumentTitleType documentTitleType, ExtendedSignerDetailsToPost signerDetails) throws IOException, DiadocSdkException {
        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (thumbprint == null) {
            throw new IllegalArgumentException("thumbprint");
        }

        try {
            var result = diadocHttpClient.performRequest(
                    RequestBuilder.post(
                            new URIBuilder(diadocHttpClient.getBaseUrl())
                                    .setPath("/V2/ExtendedSignerDetails")
                                    .addParameter("boxId", boxId)
                                    .addParameter("thumbprint", thumbprint)
                                    .addParameter("documentTitleType", Integer.toString(documentTitleType.getNumber())).build())
                            .setEntity(new ByteArrayEntity(signerDetails.toByteArray())));
            return ExtendedSignerDetails.parseFrom(result);

        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }
} public class TemplateClient {
    private DiadocHttpClient diadocHttpClient;

    public TemplateClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public Template postTemplate(TemplateToPost templateToPost) throws DiadocSdkException {
        if (templateToPost == null) {
            throw new IllegalArgumentException("templateToPost");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl()).setPath("/PostTemplate").build())
                    .setEntity(new ByteArrayEntity(templateToPost.toByteArray()));

            return Template.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public Message transformTemplateToMessage(TemplateTransformationToPost templateTransformationToPost) throws DiadocSdkException {
        if (templateTransformationToPost == null) {
            throw new IllegalArgumentException("templateTransformationToPost");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl()).setPath("/TransformTemplateToMessage").build())
                    .setEntity(new ByteArrayEntity(templateTransformationToPost.toByteArray()));

            return Message.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    /**
     * Use getMessage from message client instead
     */

    @Deprecated
    public Template getTemplate(String currentBoxId, String templateId, @Nullable String entityId) throws DiadocSdkException {
        if (currentBoxId == null) {
            throw new IllegalArgumentException("currentBoxId");
        }
        if (templateId == null) {
            throw new IllegalArgumentException("templateId");
        }

        try {
            var url = new URIBuilder(diadocHttpClient.getBaseUrl())
                    .setPath("/GetTemplate")
                    .addParameter("boxId", currentBoxId)
                    .addParameter("templateId", templateId);

            if(!Tools.isNullOrEmpty(entityId)){
                url.addParameter("entityId", entityId);
            }

            var request = RequestBuilder.get(url.build());

            return Template.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public MessagePatch postTemplatePatch(
            String boxId,
            String templateId,
            DiadocMessage_PostApiProtos.TemplatePatchToPost templatePatchToPost) throws DiadocSdkException {

        if (boxId == null) {
            throw new IllegalArgumentException("boxId");
        }
        if (templateId == null) {
            throw new IllegalArgumentException("templateId");
        }
        if (templatePatchToPost == null) {
            throw new IllegalArgumentException("templatePatchToPost");
        }

        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/PostTemplatePatch")
                            .addParameter("boxId", boxId)
                            .addParameter("templateId", templateId)
                            .build())
                    .setEntity(new ByteArrayEntity(templatePatchToPost.toByteArray()));

            return MessagePatch.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }
} public class UserClient {
    private DiadocHttpClient diadocHttpClient;

    public UserClient(DiadocHttpClient diadocHttpClient) {
        this.diadocHttpClient = diadocHttpClient;
    }

    public User getMyUser() throws DiadocSdkException {
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl()).setPath("/GetMyUser").build());
            return User.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public UserV2 getMyUserV2() throws DiadocSdkException {
        try {
            var request = RequestBuilder.get(
                    new URIBuilder(diadocHttpClient.getBaseUrl()).setPath("/V2/GetMyUser").build());
            return UserV2.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

    public UserV2 updateMyUser(UserToUpdate userToUpdate) throws DiadocSdkException {
        if (userToUpdate == null) {
            throw new IllegalArgumentException("userToUpdate");
        }
        try {
            var request = RequestBuilder.post(
                    new URIBuilder(diadocHttpClient.getBaseUrl())
                            .setPath("/UpdateMyUser")
                            .build())
                    .setEntity(new ByteArrayEntity(userToUpdate.toByteArray()));
            return UserV2.parseFrom(diadocHttpClient.performRequest(request));
        } catch (URISyntaxException | IOException e) {
            throw new DiadocSdkException(e);
        }
    }

}
import Diadoc.Api.auth.AuthManager;
import Diadoc.Api.auth.AuthenticateClient;
import Diadoc.Api.counteragent.CounteragentClient;
import Diadoc.Api.department.DepartmentClient;
import Diadoc.Api.docflow.DocflowClient;
import Diadoc.Api.document.DocumentClient;
import Diadoc.Api.documentType.DocumentTypeClient;
import Diadoc.Api.employee.EmployeeClient;
import Diadoc.Api.events.EventsClient;
import Diadoc.Api.generateTitle.GenerateClient;
import Diadoc.Api.httpClient.DiadocHttpClient;
import Diadoc.Api.message.MessageClient;
import Diadoc.Api.organizations.OrganizationClient;
import Diadoc.Api.parse.ParseClient;
import Diadoc.Api.print.PrintFormClient;
import Diadoc.Api.shelf.ShelfClient;
import Diadoc.Api.sign.SignClient;
import Diadoc.Api.template.TemplateClient;
import Diadoc.Api.user.UserClient;
import org.apache.http.HttpHost;
import org.jetbrains.annotations.Nullable;
package Diadoc.Api;


public class DiadocApi {

    private AuthManager authManager;
    private AuthenticateClient authClient;
    private OrganizationClient organizationClient;
    private DepartmentClient departmentClient;
    private EmployeeClient employeeClient;
    private UserClient userClient;
    private CounteragentClient counteragentClient;
    private GenerateClient generateClient;
    private ShelfClient shelfClient;
    private MessageClient messageClient;