/*
 *  Copyright 2015 Red Hat, Inc.
 *
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  and Apache License v2.0 which accompanies this distribution.
 *
 *  The Eclipse Public License is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 *  The Apache License v2.0 is available at
 *  http://www.opensource.org/licenses/apache2.0.php
 *
 *  You may elect to redistribute this code under either of these licenses.
 */

package io.vertx.ext.asyncsql.impl.pool;

import com.github.mauricio.async.db.Configuration;
import com.github.mauricio.async.db.Connection;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.ext.asyncsql.impl.ScalaUtils;
import io.vertx.ext.asyncsql.impl.VertxEventLoopExecutionContext;

import java.util.ArrayList;
import java.util.List;

/**
 * Manages a pool of connection.
 *
 * @author <a href="http://escoffier.me">Clement Escoffier</a>
 */
public abstract class AsyncConnectionPool {

  private final int maxPoolSize;

  private static final Logger logger = LoggerFactory.getLogger(AsyncConnectionPool.class);
  protected final Configuration configuration;
  protected final Vertx vertx;

  private int poolSize = 0;
  private final List<Connection> availableConnections = new ArrayList<>();
  private final List<Handler<AsyncResult<Connection>>> waiters = new ArrayList<>();

  public AsyncConnectionPool(Vertx vertx, int maxPoolSize, Configuration configuration) {
    this.vertx = vertx;
    this.maxPoolSize = maxPoolSize;
    this.configuration = configuration;
  }

  protected abstract Connection create();

  private synchronized void createConnection(Handler<AsyncResult<Connection>> handler) {
    poolSize += 1;
    try {
      Connection connection = create();
      connection
          .connect().onComplete(ScalaUtils.toFunction1(handler), VertxEventLoopExecutionContext.create(vertx));
    } catch (Throwable e) {
      logger.info("creating a connection went wrong", e);
      poolSize -= 1;
      handler.handle(Future.failedFuture(e));
    }
  }

  private synchronized void waitForAvailableConnection(Handler<AsyncResult<Connection>> handler) {
    waiters.add(handler);
  }

  private synchronized void createOrWaitForAvailableConnection(Handler<AsyncResult<Connection>> handler) {
    if (poolSize < maxPoolSize) {
      createConnection(handler);
    } else {
      waitForAvailableConnection(handler);
    }
  }

  public synchronized void take(Handler<AsyncResult<Connection>> handler) {
    if (availableConnections.isEmpty()) {
      createOrWaitForAvailableConnection(handler);
    } else {
      Connection connection = availableConnections.remove(0);
      if (connection.isConnected()) {
        handler.handle(Future.succeededFuture(connection));
      } else {
        poolSize -= 1;
        take(handler);
      }
    }
  }

  private synchronized void notifyWaitersAboutAvailableConnection() {
    if (!waiters.isEmpty()) {
      Handler<AsyncResult<Connection>> handler = waiters.remove(0);
      take(handler);
    }
  }

  public synchronized void giveBack(Connection connection) {
    if (connection.isConnected()) {
      availableConnections.add(connection);
    } else {
      poolSize -= 1;
    }
    notifyWaitersAboutAvailableConnection();
  }

  public synchronized void close() {
    availableConnections.forEach(Connection::disconnect);
  }

  public synchronized void close(Handler<AsyncResult<Void>> handler) {
    close();
    if (handler != null) {
      handler.handle(Future.succeededFuture());
    }
  }
}

@@ -998,20 +998,21 @@
 il.Array
-List
+Deque
 ;%0Aimport
@@ -1022,20 +1022,21 @@
 va.util.
-List
+Deque
 ;%0A%0A/**%0A 
@@ -1430,20 +1430,21 @@
 e final 
-List
+Deque
 %3CConnect
@@ -1476,28 +1476,29 @@
  = new Array
-List
+Deque
 %3C%3E();%0A  priv
@@ -1507,20 +1507,21 @@
 e final 
-List
+Deque
 %3CHandler
@@ -1570,12 +1570,13 @@
 rray
-List
+Deque
 %3C%3E()
@@ -2722,42 +2722,87 @@
     
-if (availableConnections.isEmpty()
+Connection connection = availableConnections.poll();%0A    if (connection == null
 ) %7B%0A
@@ -2869,70 +2869,8 @@
 e %7B%0A
-      Connection connection = availableConnections.remove(0);%0A
     
@@ -3117,40 +3117,8 @@
 ) %7B%0A
-    if (!waiters.isEmpty()) %7B%0A  
     
@@ -3172,18 +3172,42 @@
 ers.
-remove(0);
+poll();%0A    if (handler != null) %7B
 %0A   

Replace ArrayList by ArrayDeque in AsyncConnectionPool