// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "aemu/base/Log.h"
#include "aemu/base/async/AsyncSocketAdapter.h"
#include "aemu/base/async/AsyncWriter.h"
#include "aemu/base/async/Looper.h"
#include "aemu/base/containers/BufferQueue.h"
#include "aemu/base/sockets/SocketUtils.h"
#include "aemu/base/synchronization/Lock.h"
#include "aemu/base/threads/FunctorThread.h"
#include "aemu/base/sockets/ScopedSocket.h"

namespace android {
namespace base {
using MessageQueue = android::base::BufferQueue<std::string>;
using android::base::AsyncSocketAdapter;
using android::base::FunctorThread;

// An AsyncSocket is a socket that can connect to a local port on
// the current machine.
class AsyncSocket : public AsyncSocketAdapter {
public:
    AsyncSocket(Looper* looper, int port);
    AsyncSocket(Looper* looper, ScopedSocket socket);
    ~AsyncSocket();
    void close() override;
    uint64_t recv(char* buffer, uint64_t bufferSize) override;
    uint64_t send(const char* buffer, uint64_t bufferSize) override;

    bool connect() override;
    bool connected() override;
    bool connectSync(
            uint64_t timeoutms = std::numeric_limits<int>::max()) override;
    void dispose() override;

    void onWrite();
    void onRead();
    void wantRead();

private:
    void connectToPort();
    static const int WRITE_BUFFER_SIZE = 1024;

    ScopedSocket mSocket;
    int mPort;

    Looper* mLooper;
    bool mConnecting = false;

    std::unique_ptr<Looper::FdWatch> mFdWatch;
    ::android::base::AsyncWriter mAsyncWriter;
    std::unique_ptr<FunctorThread> mConnectThread;

    // Queue of message that need to go out over this socket.
    MessageQueue mWriteQueue;
    Lock mWriteQueueLock;
    Lock mWatchLock;
    ConditionVariable mWatchLockCv;

    // Write buffer used by the async writer.
    std::string mWriteBuffer;
};
}  // namespace base
}  // namespace android
