/*
 * 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.
 */
package com.facebook.presto.recordservice;

import com.cloudera.recordservice.core.RecordServiceException;
import com.cloudera.recordservice.core.Records;
import com.facebook.presto.spi.RecordCursor;
import com.facebook.presto.spi.type.Type;
import io.airlift.log.Logger;
import io.airlift.slice.Slice;

import java.io.IOException;

public class RecordServiceRecordCursor implements RecordCursor
{
  private static final Logger log = Logger.get(RecordServiceSplitManager.class);
  private final Records records;

  public RecordServiceRecordCursor(Records records)
  {
    this.records = records;
  }

  @Override
  public long getTotalBytes()
  {
    throw new UnsupportedOperationException();
  }

  @Override
  public long getCompletedBytes()
  {
    try {
      return records.getStatus().stats.bytesRead;
    }
    catch (IOException e) {
      log.error("Failed to getCompletedBytes.", e);
    }
    catch (RecordServiceException e) {
      log.error("Failed to getCompletedBytes.", e);
    }
    throw new RuntimeException("Failed to getCompletedBytes");
  }

  @Override
  public long getReadTimeNanos()
  {
    try {
      return records.getStatus().stats.clientTimeMs;
    }
    catch (IOException e) {
      log.error("Failed to getReadTimeNanos.", e);
    }
    catch (RecordServiceException e) {
      log.error("Failed to getReadTimeNanos.", e);
    }
    throw new RuntimeException("Failed to getReadTimeNanos");
  }

  @Override
  public Type getType(int field)
  {
    throw new UnsupportedOperationException();
  }

  @Override
  public boolean advanceNextPosition()
  {
    try {
      return records.hasNext();
    }
    catch (IOException e) {
      log.error("Failed to advanceNextPosition.", e);
    }
    catch (RecordServiceException e) {
      log.error("Failed to advanceNextPosition.", e);
    }
    return false;
  }

  @Override
  public boolean getBoolean(int field)
  {
    try {
      return records.next().nextBoolean(field);
    }
    catch (IOException e) {
      log.error("Failed to getBoolean.", e);
    }
    throw new RuntimeException("Failed to getBoolean.");
  }

  @Override
  public long getLong(int field)
  {
    try {
      return records.next().nextLong(field);
    }
    catch (IOException e) {
      log.error("Failed to getLong.", e);
    }
    throw new RuntimeException("Failed to getLong.");
  }

  @Override
  public double getDouble(int field)
  {
    try {
      return records.next().nextDouble(field);
    }
    catch (IOException e) {
      log.error("Failed to getDouble.", e);
    }
    throw new RuntimeException("Failed to getDouble.");
  }

  @Override
  public Slice getSlice(int field)
  {
    throw new UnsupportedOperationException();
  }

  @Override
  public Object getObject(int field)
  {
    throw new UnsupportedOperationException();
  }

  @Override
  public boolean isNull(int field)
  {
    throw new UnsupportedOperationException();
  }

  @Override
  public void close()
  {
    if (records != null) {
      records.close();
    }
  }
}

@@ -1066,16 +1066,53 @@
 records;
+%0A  private Records.Record nextRecord;
 %0A%0A  publ
@@ -1189,16 +1189,44 @@
 ecords;%0A
+    this.nextRecord = null;%0A
   %7D%0A%0A  @
@@ -2223,32 +2223,54 @@
 y %7B%0A      return
+ nextRecord != null %7C%7C
  records.hasNext
@@ -2560,37 +2560,189 @@
 %7B%0A      
-return records.next()
+if (nextRecord == null) %7B%0A        nextRecord = records.next();%0A      %7D%0A      Records.Record curRecord = nextRecord;%0A      nextRecord = records.next();%0A      return curRecord
 .nextBoo
@@ -2966,37 +2966,189 @@
 %7B%0A      
-return records.next()
+if (nextRecord == null) %7B%0A        nextRecord = records.next();%0A      %7D%0A      Records.Record curRecord = nextRecord;%0A      nextRecord = records.next();%0A      return curRecord
 .nextLon
@@ -3371,29 +3371,181 @@
     
-return records.next()
+if (nextRecord == null) %7B%0A        nextRecord = records.next();%0A      %7D%0A      Records.Record curRecord = nextRecord;%0A      nextRecord = records.next();%0A      return curRecord
 .nex
@@ -3973,47 +3973,260 @@
    t
-hrow new UnsupportedOperationException(
+ry %7B%0A      if (nextRecord == null) nextRecord = records.next();%0A      return nextRecord == null %7C%7C nextRecord.isNull(field);%0A    %7D catch (IOException e) %7B%0A      log.error(%22Failed to isNull.%22, e);%0A    %7D%0A    throw new RuntimeException(%22Failed to isNull.%22
 );%0A 

implement isNull in RecordServiceRecordCursor