package com.orientechnologies.orient.core.sql.executor;

import com.orientechnologies.common.concur.OTimeoutException;
import com.orientechnologies.orient.core.command.OCommandContext;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.sql.parser.OIdentifier;

import java.util.Map;
import java.util.Optional;

/**
 * Created by luigidellaquila on 17/03/17.
 */
public class CountFromClassStep extends AbstractExecutionStep {
  private final OIdentifier target;
  private final String      alias;

  private long cost = 0;

  private boolean executed = false;

  public CountFromClassStep(OIdentifier targetIndex, String alias, OCommandContext ctx, boolean profilingEnabled) {
    super(ctx, profilingEnabled);
    this.target = targetIndex;
    this.alias = alias;
  }

  @Override
  public OResultSet syncPull(OCommandContext ctx, int nRecords) throws OTimeoutException {
    getPrev().ifPresent(x -> x.syncPull(ctx, nRecords));
    return new OResultSet() {
      @Override
      public boolean hasNext() {
        return !executed;
      }

      @Override
      public OResult next() {
        if (executed) {
          throw new IllegalStateException();
        }
        long begin = profilingEnabled ? System.nanoTime() : 0;
        try {
          OClass clazz = ctx.getDatabase().getClass(target.getStringValue());
          long size = clazz.count();
          executed = true;
          OResultInternal result = new OResultInternal();
          result.setProperty(alias, size);
          return result;
        } finally {
          if(profilingEnabled){cost += (System.nanoTime() - begin);}
        }
      }

      @Override
      public void close() {

      }

      @Override
      public Optional<OExecutionPlan> getExecutionPlan() {
        return null;
      }

      @Override
      public Map<String, Long> getQueryStats() {
        return null;
      }

      @Override
      public void reset() {
        CountFromClassStep.this.reset();
      }
    };
  }

  @Override
  public void reset() {
    executed = false;
  }

  @Override
  public String prettyPrint(int depth, int indent) {
    String spaces = OExecutionStepInternal.getIndent(depth, indent);
    String result = spaces + "+ CALCULATE CLASS SIZE: " + target;
    if (profilingEnabled) {
      result += " (" + getCostFormatted() + ")";
    }
    return result;
  }

  @Override
  public long getCost() {
    return cost;
  }

}

@@ -363,16 +363,208 @@
 l;%0A%0A/**%0A
+ * Returns the number of records contained in a class (including subclasses)%0A * Executes a count(*) on a class and returns a single record that contains that value (with a specific alias).%0A *%0A
  * Creat
@@ -801,16 +801,310 @@
 false;%0A%0A
+  /**%0A   *%0A   * @param targetClass An identifier containing the name of the class to count%0A   * @param alias the name of the property returned in the result-set%0A   * @param ctx the query context%0A   * @param profilingEnabled true to enable the profiling of the execution (for SQL PROFILE)%0A   */%0A
   public
@@ -1141,21 +1141,21 @@
 r target
-Index
+Class
 , String
@@ -1273,13 +1273,13 @@
 rget
-Index
+Class
 ;%0A  

Add javadoc to CountFromClassStep (SQL)